@Bean 
UiConfiguration uiConfig() { 
	return UiConfigurationBuilder.builder() 
    .docExpansion(DocExpansion.LIST) // or DocExpansion.NONE or DocExpansion.FULL 
    .build(); 
}

source : http://springfox.github.io/springfox/docs/current/#springfox-swagger2-with-spring-mvc-and-spring-boot

 

Springfox Reference Documentation

The Springfox suite of java libraries are all about automating the generation of machine and human readable specifications for JSON APIs written using the spring family of projects. Springfox works by examining an application, once, at runtime to infer API

springfox.github.io

swagger (2.6.1)버전이 다른 경우 

@Bean
public UiConfiguration uiConfig() {
	return new UiConfiguration(
                null,
                "list",
                "alpha",
                "schema",
                UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS,
                false,
                true,
                null
        );
}

 

서비스에 어노테이션으로 aop를 조정할 수 있다. 만약 서비스에서 로그인 관련 체크를 한다면 어노테이션을 선언하고 메서드에 어노테이션을 선언하는 것 만으로 aop 를 적용할 수 있다.

1. 인터페이스 선언 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityCheck {
}

타겟을 메서드에 준다

2. 체크할 포인트를 선언 

@Aspect
@Component
public class SecurityChecker {

  private static final Logger logger = LoggerFactory.getLogger(SecurityChecker.class);

  @Pointcut("@annotation(SecurityCheck)")
  public void checkMethodSecurity() {}

  @Around("checkMethodSecurity()")
  public Object checkSecurity (ProceedingJoinPoint joinPoint) throws Throwable {
    logger.debug("Checking method security...");
    // TODO Implement security check logics here
    Object result = joinPoint.proceed();
    return result;
  }
}

TODO 부분에 실제로 체크해야할 내용을 삽입한다.

3. 서비스 메서드에 적용 

  @SecurityCheck
  @Transactional(noRollbackFor = { UnsupportedOperationException.class })
  public Message save(String text)

Ubuntu 18.04 LTS 버전을 기준으로 한다 

1. 시스템에서 쓸 수 있는 네트워크를 확인한다. (wlan0 무선랜을 확인)

$ls /sys/class/net

eth0  lo  wlan0

2. 설정을 오픈한다 

sudo vi /etc/netplan/50-cloud-init.yaml

처음 파일을 오픈하면 이런 모습임 

network:
    ethernets:
        eth0:
            dhcp4: true
            optional: true
    version: 2

3. 파일을 편집한다. eth0 을 wlan0으로 바꾸당

network:
     wifis:
       wlan0:
         dhcp4: true
         access-points:
           "olleh_WiFi_****":
             password: "와이파이비밀번호"
     version: 2

만약 고정아이피로 하고 싶다면 아래와 같이 입력하면 된다. (dhcp4: no) 를 꼭 해주자

network:
     wifis:
       wlan0:
         dhcp4: no
         addresses: [192.168.1.16/24]
         gateway4: 192.168.1.255
         nameservers:
           addresses: [168.126.63.1,168.126.63.2]
         access-points:
           "olleh_WiFi_****":
             password: "와이파이비밀번호"
     version: 2

4. 편집후 변경사항 반영

sudo netplan apply

아이피 주소를 확인한다. 

ifconfig

웹 개발을 하다보면 리스트에서 항목 중 자식 리스트를 갖는 것을 표현하고 싶을 때 유용하게 쓸 수 있다. 

 

Course League
1코스 1부
1코스 2부
2코스 1부
2코스 2부

데이터 베이스에서 4행이 리턴된다.  1코스 = {1부, 2부} , 2코스 = {1부, 2부}

Course League
1코스 [{부=1부, 코스=1코스}, {부=2부, 코스=1코스}]
2코스 [{부=1부, 코스=2코스}, {부=2부, 코스=2코스}]

화면에서는 위와 같이 2행으로 보여주려면 어떻게 해야 할까? 

Java Stream GroupBy을 이용하여 변경할 수 있다.

 

기본 데이터 

List<Map<String, String>> list = new ArrayList<>();

Map<String, String> course1_1 = new HashMap<>();
course1_1.put("코스", "1코스");
course1_1.put("부", "1부");
Map<String, String> course2_2 = new HashMap<>();
course2_2.put("코스", "2코스");
course2_2.put("부", "2부");

Map<String, String> course2_1 = new HashMap<>();
course2_1.put("코스", "2코스");
course2_1.put("부", "1부");

Map<String, String> course1_2 = new HashMap<>();
course1_2.put("코스", "1코스");
course1_2.put("부", "2부");

list.add(course1_1);
list.add(course1_2);
list.add(course2_1);
list.add(course2_2);

Stream 에 group by  를 활용

List<Map> newList = list.stream()
  .collect(Collectors.groupingBy((map) -> map.get("코스")))
  .entrySet().stream()
  .sorted((a, b) -> b.getKey().compareTo(a.getKey()))
  .map(entry -> {
    Map map = new HashMap();
    map.put("course", entry.getKey());
    map.put("league", entry.getValue());
    return map;
  })
  .collect(Collectors.toList());

결과는 

courseAndData = {league=[{부=1부, 코스=2코스}, {부=2부, 코스=2코스}], course=2코스}
courseAndData = {league=[{부=1부, 코스=1코스}, {부=2부, 코스=1코스}], course=1코스}
computeIfAbsent​(K key, Function<? super K,​? extends V> mappingFunction)
putIfAbsent​(K key, V value)
computeIfPresent​(K key, BiFunction<? super K,​? super V,​? extends V> remappingFunction)
compute​(K key, BiFunction<? super K,​? super V,​? extends V> remappingFunction)

computeIfAbsent 와 putIfAbsent 

자바에서 맵에서 특정 키(Key)들에 항목(Value)을 넣어주고 싶은 경우가 있다. 

 

Key Value
1 KOREA
2 USA
4 JAPAN
? ?

추가되는 키가 없을 경우 함수를 호출해서 항목을 넣어줄 수 있다.

 

만약 키 값이 4 = CHINA , 5 = CANADA 를 리턴하는 함수 선언

private String getCountry(String key){
	System.out.println("@@@@@ : " + key);
	return key.equals("4") ? "CHINA" : "CANADA";
}

맵에는 1,2,3 에 대한 값만 있고, 키 리스트는 1,2,3,4,5 일 경우 

computeIfAbsent를 이용하여 4,5에 값을 넣을 수 있다.

List<String> keyList = new ArrayList<>();
keyList.add("1");
keyList.add("2");
keyList.add("3");
keyList.add("4");
keyList.add("5");

Map<String, String> map = new HashMap<>();
map.put("1", "KOREA");
map.put("2", "USA");
map.put("3", "JAPAN");

for(String s : keyList){
	map.computeIfAbsent( s, (key) -> getCountry(key) );
}

System.out.println("map = " + map);

결과는 putIfAbsent 도 동일한 결과를 보여준다

map = {1=KOREA, 2=USA, 3=JAPAN, 4=CHINA, 5=CANADA}

computeIfAbsent 와 putIfAbsent 차이

putIfAbsent는 키(Key)가 있음에도 함수를 호출함 (*단 항목을 변경하지 않음)

 

computeIfAbsent 의 결과 출력

@@@@@ : 4
@@@@@ : 5
map = {1=KOREA, 2=USA, 3=JAPAN, 4=CHINA, 5=CANADA}

putIfAbsent 의 결과 출력

@@@@@ : 1
@@@@@ : 2
@@@@@ : 3
@@@@@ : 4
@@@@@ : 5
map = {1=KOREA, 2=USA, 3=JAPAN, 4=CHINA, 5=CANADA}

computeIfPresent 와 compute

단어의 빈도 수를 체크하는 프로그램을 만들 때

어떤 단어가 몇 번 나왔는지 체크할때 유용하게 사용할 수있다.

 

text에 단어가 몇 번 나왔는지 맵에 저장, 일단 초기값은 0 이다.

String text = "KOREA KOREA USA USA USA CANADA JAPAN ";

Map<String, Integer> wordMap = new HashMap<>();

wordMap.put("KOREA", 0);
wordMap.put("USA", 0);
wordMap.put("CHINA", 0);
wordMap.put("JAPAN", 0);

 

computeIfPresent 을 이용하여 빈도 수를 계산한다.

for(String word : text.split(" ")){
	wordMap.computeIfPresent(word, (String key, Integer value) ->  ++value);
}

System.out.println("wordMap = " + wordMap);

 

결과는... 

wordMap = {USA=3, CHINA=0, JAPAN=1, KOREA=2}

computeIfPresent 와 compute 차이

위에 결과를 compute로 바꾸면 에러(NullPointerException)가 발생한다. 

CANADA가 없기 때문이다. CANADA가 없다면 결과는 동일하다. 

 

그리고 ... getOrDefault

값이 없을 때 널을 피하기 위하여 디폴트를 지정할 수 있다. 

Map<String, String> map = new HashMap<>();
map.put("1", "KOREA");
map.put("2", "USA");

System.out.println("map = " + map.getOrDefault("3", "FRANCE"));
System.out.println("map = " + map.get("3"));

결과는...

map = FRANCE
map = null
  1. HttpServletRequest.getUserPrincipal() 으로 현재 사용자 정보를 가져올 수 있다.  
  2. SecurityContextHolder로 SecurityContextHolder.getContext().getAuthentication() 
  3. 스프링 시큐리트의 @AuthenticationPrincipal이 적용된 어노테이션을 생성할 있다. 그리고 스프링에 UserDetails 구현체를 API 핸들러 메소드에 주입하여 요청

3번의 예제

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {
}

Controller 에서 변환하여 사용

public ResponseEntity<ApiResult> createBoard(
            @RequestBody CreateBoardPayload payload,
            @CurrentUser SimpleUser currentUser) {
...
spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/task_agile_test
    username: sa
    password:
    driver-class-name: org.h2.Driver

  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    open-in-view: false
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        show_sql: true
        format_sql: true
        
logging:
  level:
    org.hibernate.type.descriptor.sql: trace
  • spring.datasource : DB 연결정보 
  • spring.jpa.database-platform : 데이터 플래폼을 지정, 참고 
  • spring.jpa.open-in-view : osiv 웹요청이 완료될때까지 영속성을 가짐 (성능상 안 좋음)
  • spring.jpa.hibernate.ddl-auto :
    • none : No action is performed. The schema will not be generated.
    • create : create the schema, the data previously present (if there) in the schema is lost
    • create-drop : (default) create the schema with destroying the data previously present(if there). It also drop the database schema when the SessionFactory is closed.
    • update : update the schema with the given values.
    • validate : validate the schema. It makes no change in the DB.
  • spring.jpa.properties.hibernate.format_sql : 실행쿼리를 가독성있게 표현
  • spring.jpa.properties.hibernate.show-sql : 콘솔에 jpa 실행쿼리
  • logging.level.org.hibernate.type.descriptor.sql : ? 부문을 로그로 출력해줌

https://github.com/FortAwesome/vue-fontawesome

 

FortAwesome/vue-fontawesome

Font Awesome 5 Vue component. Contribute to FortAwesome/vue-fontawesome development by creating an account on GitHub.

github.com

위 링크를 참조하였음

 

NPM 으로 설치

$ npm i --save @fortawesome/fontawesome-svg-core
$ npm i --save @fortawesome/free-solid-svg-icons
$ npm i --save @fortawesome/vue-fontawesome

vue /src/main.js 에서 설정

import { library as faLibrary } from '@fortawesome/fontawesome-svg-core'
import { faHome, faSearch, faPlus } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'

// Set up FontAwesome
faLibrary.add(faHome, faSearch, faPlus)
Vue.component('font-awesome-icon', FontAwesomeIcon)

화면에서 사용

<font-awesome-icon icon="plus" />

+ Recent posts