반응형
반응형

 

📝전체 URL 적용

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("*") // 모든 origin 허용 (보안상 주의)
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*");
    }
}

 

  • addMapping
    • 내가 작성한 어떤 라우팅에 대해서 CORS를 허용할 지
  • allowedOrigins
    • 어떤 요청자에 대해서 허용시킬 것인지
  • allowedMethods
    • 어떤 HTTP 메소드에 대해서 허용할지
  • allowedHeaders
    • 어떤 헤더 값에 대해서 허용할지

 

📝부분 라우팅 적용

@CrossOrigin(origins = "*")
@GetMapping("/next")
public @ResponseBody HashMap<String, Object> next() throws InterruptedException {

	System.out.println("next2 call!!");
	HashMap<String, Object> map = new HashMap<String, Object>();
	map.put("id", "Next 테스트");
	
	Thread.sleep(3000);
	
	return map;
}
반응형
반응형

 

📝@Rollback

@Transactional
@Rollback(value = false)
class MemberRepositoryTest {
    ...
}

@Transactional에서 장애 발생시 롤백 시키는 걸 할지 말지에 대한 것이다. 일반적으로 사용하지 않으며 테스트 코드 작성해서 디비 데이터 값을 확인해야한다면 사용한다 (테스트 코드 작동한 후 종료된 뒤에 바로 롤백 시켜서 디비에서 확인하기가 어려움)

 

📝@PostConstruct

// 초기 데이터 INSERT
@PostConstruct
public void insertData() throws Exception {

    IntStream.range(0, 100).forEach((i) -> {
        Member member = new Member("username" + i);
        memberRepository.save(member);
    });
}

종속성 주입이 완료된 후 실행되어야 하는 메서드에 사용한다 여기에서는 정상으로 스프링부트가 기동 된다면 해당 메소드가 동작해 초기 데이터를 INSERT하는 작업이다.

 

📝@CrossOrign

@CrossOrigin(origins = "*")
@GetMapping("/next")
public @ResponseBody HashMap<String, Object> next() throws InterruptedException {

	System.out.println("next2 call!!");
	HashMap<String, Object> map = new HashMap<String, Object>();
	map.put("id", "Next 테스트");
	
	Thread.sleep(3000);
	
	return map;
}

어떤 라우팅에 대해서 URL 요청을 허용할 지

반응형
반응형

📝@EnableJpaAuditing, @EntityListeneres, @CreateBy, @LastModifiedBy, @CreateDate, @LastModifiedDate

@EnableJpaAuditing // 필수
@SpringBootApplication
public class DataJpaApplication {

	public static void main(String[] args) {
		SpringApplication.run(DataJpaApplication.class, args);
	}

	@Bean
	public AuditorAware<String> auditorProvider() {
		return () -> Optional.of(UUID.randomUUID().toString());
		// 실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받음
	}

}

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity {

    @CreatedBy
    @Column(updatable = false)
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;

}

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseTimeEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createDate;

    @LastModifiedDate
    private LocalDateTime lastModifiedDate;

}


@Entity
public class Member extends BaseEntity {

    @Id
    @GeneratedValue
    private String id;
    
    private String username;

}

 

  • @EnableJpaAuditing
    • 아래 어노테이션을 쓰기 위해 필수 기능이다
  • @EntityListeneres
    • 해당 엔터티는 JPA Entity에 이벤트 발생시 콜백 처리하라는 의미이다.
  • @CreateBy
    • 생성자
  • @LastModifiedBy
    • 수정자
  • @CreateDate
    • 등록일자
  • @LastModifiedDate
    • 수정일자

 

📝@PersistenceContext

@PersistenceContext
EntityManager em;

스프링 부트에서 생성한 EntityManager를 DI시켜준다

반응형
반응형

📝@NamedQuery, @Query

@Entity
@NamedQuery(
    name="Member.findByUsername", // Key
    query="select m from Member m where m.username = :username" // Value
)
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String username;
    private int age;

}

public interface MemberRepository extends JpaRepository<Member, Long> {

    /** ----- 방법1 (@Query) ----- **/
    @Query(name ="Member.findByUsername")
    List<Member> findByUsername(@Param("username") String username);
    
    /** ----- 기본 예제 ----- **/
    @Query("select m from Member m where m.username = :username and m.age = :age")
    List<Member> findUser(@Param("username") String username, @Param("age") int age);

}

조건절 조회하는 임의의 쿼리가 필요할 때 Entity에 @NamedQuery를 이용해 JpaRepository에서 {키:값} 형태로 찾아 사용이 가능하다

이 방법보단 JpaRepository에서 바로 @Query를 이용해 바로 작성하는 걸 더 많이 사용한다

 

📝@Modifying

public interface MemberRepository extends JpaRepository<Member, Long> {

    @Modifying(clearAutomatically = true)
    @Query("update Member m set m.age = m.age + 1 where m.age >= :age")
    int bulkAgePlus(@Param("age") int age);
 
}

Update한 후에 Update 항목을 조회하는 경우가 있을 때 영속성 컨텍스트 캐시를 날리고 데이터 조회하기 때문에 디비에서 조회하게 되고  데이터의 정합성을 맞춘다

 

📝@EntityGraph

public interface MemberRepository extends JpaRepository<Member, Long> {

    @EntityGraph(attributePaths = {"team"})
    @Query("select m from Member m")
    // 위에 코드는 EntityGraph + Query로 아래와 같은 코드이다. (team Fetch Join)

    // @Query("select m from Member m left join fetch m.team")
    List<Member> findMemberEntityGraph();
}

패치조인을 더 쉽게할 수 있도록 스프링 데이터 JPA에서 제공해준다.

 

📝엔터티 라이프 사이클 컨트롤 어노테이션

@PrePersist : 새로운 엔티티에 대해 persist가 호출되기 전
@PreUpdate : 엔티티 업데이트 작업 전
@PreRemove : 엔티티가 제거되기 전
@PostPersist : 새로운 엔티티에 대해 persist가 호출된 후
@PostUpdate : 엔티티가 업데이트된 후
@PostRemove : 엔티티가 삭제된 후
@PostLoad : Select조회가 일어난 직후에 실행

 

 

 

반응형
반응형

📝@Entity, @Id, @GeneratedValue, @Temporal, @Lob

public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // IDENTITY 전략
    // @GeneratedValue(strategy = GenerationType.SEQUENCE) // SEQUENCE 전략
    @Column(name="member_id")
    private Long id;

    private String name;
    private int age;
    private String address; // 필드만 추가해주면 끝

    // @Enumerated(EnumType.ORDINAL) // enum 타입 매핑 [숫자] (금지)
    @Enumerated(EnumType.STRING) // enum 타입 매핑 [문자] (사용 OK)
    private CategoryEnum name;

    // 날짜 타입 매핑 [아래 LocalDateTime을 쓰면 알아서 YYYYMMDDHHMMSS 설정]
    @Temporal(TemporalType.DATE) 
    private Date date;
    
    private LocalDateTime createDate
    
    @Lob // BLOB, CLOB 매핑
    private String description;
}

 

  • @Entity 
    • JPA에서 영속성 컨텍스트가 관리할 테이블이라는 의미이다.
  • @Id
    • 해당 필드를 PK로 지정하겠다는 의미이다.
  • @GeneratedValue
    • PK AutoIncrement설정이다. IDENTITY로 설정할지 SEQUENCE로 지정할지 정할 수 있다.
  • @Temporal
    • 날짜 필드라는 걸 알리는 의미이다.
  • @Lob
    • BLOB, CLOB타입이라는 걸 알리는 의미이다.

 

📝@JoinColumn, @ManyToOne, @OneToMany, @OneToOne, @ManyToMany

@Entity
public class Member {

    @Id // PK로 설정할 컬럼
    @GeneratedValue
    private long id;

    @Column(nullable = false, length = 10)
    private String name;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // Team 테이블[클래스]에 연결할 필드명을 알려주세요 
                                  // (JoinColumn은 FK가 있는 테이블에 들어간다)
    private Team team;

}

@Entity
public class Team {

    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;

}
  • @JoinColumn
    • 연결할 테이블에 필드를 지정한다
  • @ManyToOne
    • 다대일 관계로 연결하겠다는 의미
  • @OneToMany
    • 일대다 관계로 연결하겠다는 의미
  • @OneToOne
    • 일대일 관계로 연결하겠다는 의미
  • @ManyToMany (사용 X)
    • 다대다 관계로 연결하겠다는 의미 (다대다 관계는 무조건 다대일로 풀어내야한다)

 

 

📝@Inheritance, @DiscriminatorColumn, @DiscriminatorValue

@Inheritance(strategy = InheritanceType.JOINED) // 조인 전략
@DiscriminatorColumn 
@Entity
public class Item {

    @Id
    @GeneratedValue
    private long id;

    private String name;
    private int price;
}

@Entity
// @DiscriminatorValue("this is movie")
public class Movie extends Item{

    private String director;
    private String actor;

}

public class Main {
    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        tx.begin();

        try{

            Movie movie = new Movie();
            movie.setName("바람과 함께 사라지다");
            movie.setPrice(10000);
            movie.setActor("이민호");
            movie.setDirector("봉준호");

            em.persist(movie);

            tx.commit();

        }catch (Exception e){
            e.printStackTrace();
        }finally{
            emf.close();
            em.close();
        }
    }
}

 

@Inheritance

관계형 데이터베이스에 상속관계라는 걸 JPA에서 표현했다

 

 

 

 

@DiscriminatorColumn

해당 어노테이션을 사용 안 하면 DTYPE이 따로 안 보이는데 이걸 명시적으로 표현해주는 어노테이션 어느 자식이 UPSERT 되어서 그런지 잘 모르니 해당 어노테이션을 사용하는게 좋다

 

 

 

 

@DiscriminatorValue

해당 어노테이션을 사용하면 DTYPE에 들어갈 걸 명시적으로 지정할 수 있다.

 

 

 

 

 

 

 

 

📝@MappedSuperclass

@MappedSuperclass
public abstract class BaseEntity {

    @Column(name = "create_date") // 부모 클래스에서 컨트롤 가능
    private LocalDateTime localDateTime;

    private LocalDateTime modi_date;
}

@Entity
public class Book extends BaseEntity{

    @Id
    @GeneratedValue
    private long id;

    private String name;
    private String author;
    private String ISBN;

}

Inheritance와 차이가 있는 점은 Inheritance은 부모 자식 테이블 따로따로 들어가게 되는데 MappedSuperclass의 경우 필드만 공유하고 하나의 테이블로 만들어진다.

 

 

📝@NamedQuery, @Query

@Entity
@NamedQuery(
    name="Member.findByUsername", // Key
    query="select m from Member m where m.username = :username" // Value
)
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String username;
    private int age;

}

public interface MemberRepository extends JpaRepository<Member, Long> {

    /** ----- 방법1 (@Query) ----- **/
    @Query(name ="Member.findByUsername")
    List<Member> findByUsername(@Param("username") String username);
    
    /** ----- 기본 예제 ----- **/
    @Query("select m from Member m where m.username = :username and m.age = :age")
    List<Member> findUser(@Param("username") String username, @Param("age") int age);

}

조건절 조회하는 임의의 쿼리가 필요할 때 Entity에 @NamedQuery를 이용해 JpaRepository에서 {키:값} 형태로 찾아 사용이 가능하다

이 방법보단 JpaRepository에서 바로 @Query를 이용해 바로 작성하는 걸 더 많이 사용한다

 

📝@Modifying

public interface MemberRepository extends JpaRepository<Member, Long> {

    @Modifying(clearAutomatically = true)
    @Query("update Member m set m.age = m.age + 1 where m.age >= :age")
    int bulkAgePlus(@Param("age") int age);
 
}

Update한 후에 Update 항목을 조회하는 경우가 있을 때 영속성 컨텍스트 캐시를 날리고 데이터 조회하기 때문에 디비에서 조회하게 되고  데이터의 정합성을 맞춘다

 

📝@EntityGraph

public interface MemberRepository extends JpaRepository<Member, Long> {

    @EntityGraph(attributePaths = {"team"})
    @Query("select m from Member m")
    // 위에 코드는 EntityGraph + Query로 아래와 같은 코드이다. (team Fetch Join)

    // @Query("select m from Member m left join fetch m.team")
    List<Member> findMemberEntityGraph();
}

패치조인을 더 쉽게할 수 있도록 스프링 데이터 JPA에서 제공해준다.

 

엔터티 라이프 사이클 컨트롤 어노테이션 (@PrePersist, @PreUpdate, @PreRemove, @PostPersist, @PostUpdate, @PostRemove, @PostLoad)

@PrePersist : 새로운 엔티티에 대해 persist가 호출되기 전
@PreUpdate : 엔티티 업데이트 작업 전
@PreRemove : 엔티티가 제거되기 전
@PostPersist : 새로운 엔티티에 대해 persist가 호출된 후
@PostUpdate : 엔티티가 업데이트된 후
@PostRemove : 엔티티가 삭제된 후
@PostLoad : Select조회가 일어난 직후에 실행
반응형
반응형

📝 @Getter, @Setter, @RequriedArgsConstructor, @Data, @AllArgsConstruct, @NoArgsConstructor (롬복 필요)

@Getter // Getter 생성
@Setter // Setter 생성 
@RequiredArgsConstructor // 생성자 DI
@Data // Getter + Setter 생성
@AllArgsConstructor // 생성자 생성
@NoArgsConstructor // 기본생성자
@ToString(of = {"id","password"})
public class Account {

	// private final String id; // DB에서 값을 받아와 수정할 일이 없을 때는 final 로 쓰는게 trend
	// private final int password; // DB에서 값을 받아와 수정할 일이 없을 때는 final 로 쓰는게 trend 
	private String id;
	private int password;
	
	@Builder // 내가 원하는 생성자 파라미터 지정 가능
	public Account(String id, int password) {
		this.id = id;
		this.password = password;
	}
	
}

 

 

📝 @ResponseStatus

@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-json-v2")
public String responseBodyJsonV2() {

    String logInfo = "abc";
    log.info("log : {}", logInfo);

    return logInfo;
}

HTTP 통신 상태 코드값을 지정할 수 있습니다.

 

📝 @ExceptionHandler

public class ApiExceptionV2Controller {

	...
    @ResponseStatus(HttpStatus.BAD_REQUEST) // 해당 Status 설정 없으면 200(정상)이 나가기 때문에 따로 설정 필요
    @ExceptionHandler(IllegalArgumentException.class) // 해당 컨트롤러에서만 IllegalArgumentException 발생 시 작동
    public ErrorResult illegalExHandler(IllegalArgumentException e){
        log.error("[exception] ex",e);
        return new ErrorResult("BAD",e.getMessage());
        /**
         * {
         *   "code": "BAD",
         *   "message": "잘못된 입력 값"
         * }
         */
    }
    
    @GetMapping("/api2/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id) {

        if (id.equals("ex")) {
            throw new RuntimeException("잘못된 사용자");
        }
        if (id.equals("bad")) {
            throw new IllegalArgumentException("잘못된 입력 값");
        }
        if (id.equals("user-ex")) {
            throw new UserException("사용자 오류");
        }

        return new MemberDto(id, "hello " + id);
    }
}

 

 

현 컨트롤러 내에서 지정한 에러 발생시 핸들링할 수 있는 역할을 한다

 

📝 @Transactional

@Transactional
public void updateSomething(MembmerDto membmerDto){

    // ... 업데이트
    // 실패!! -> RollBack

}

 

📝 @TestConfiguration

@TestConfiguration
static class TestConfig {

    private final DataSource dataSource;

    public TestConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    MemberRepositoryV3 memberRepositoryV3() {
        return new MemberRepositoryV3(dataSource);
    }

    @Bean
    MemberServiceV3_3 memberServiceV3_3() {
        return new MemberServiceV3_3(memberRepositoryV3());
    }

}

테스트 환경에서 @Configuration역할을 한다.

반응형
반응형

📝 @RequestMapping, @Responsebody

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
    /**
     * GET /mapping/users
     */
    @GetMapping
    public String users() {
        return "get users";
    }
    /**
     * POST /mapping/users
     */
    @PostMapping
    public String addUser() {
        return "post user";
    }
    /**
     * GET /mapping/users/{userId}
     */
    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId) {
        return "get userId=" + userId;
    }
    /**
     * PATCH /mapping/users/{userId}
     */
    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId) {
        return "update userId=" + userId;
    }
}
  • 일반적으로 공통적인 URL을 클래스 위에 선언해 사용한다

 

@RequestMapping(value = "/modelAndView.do" method = RequestMethod.GET)
public ModelAndView returnModelAndView(HttpServletResponse response,
        HttpServletRequest request) {
    ModelAndView modelAndView = new ModelAndView();

    // WEB-INF/views/가 기본 경로
    modelAndView.setViewName("request"); // request.jsp 페이지 노출 WEB-INF/views/request.jsp
    modelAndView.addObject("name","James"); // index.jsp에 name : James 값을 전달

    return modelAndView;

}

 

리턴 종류  - ModelAndView 

  • 노출시킬 jsp 페이지와 값을 보낼 수 있습니다.
@RequestMapping(value = "/string.do")
public String returnString(HttpServletResponse response,
        HttpServletRequest request) {

    return "request"; // request.jsp 페이지 노출
}

 

리턴 종류 - String

  • return 값에 해당하는 jsp 페이지를 노출시킵니다.
@RequestMapping("/requset.do")
    public void request(HttpServletResponse response,
            HttpServletRequest request) throws IOException {

    PrintWriter writer = null;

    writer=response.getWriter();
    writer.print("<html><body><h1>Hello, ResponseBody!</h1></body></html>");
    writer.flush();
}

 

리턴 종류 - void

  • HTML 태그를 인식할 수 있습니다. 노출 페이지는 없지만 직접 만들 수 있습니다.

 

@RequestMapping(value = "/string2.do")
@ResponseBody
public String returnString2(HttpServletResponse response,
        HttpServletRequest request) {

    return "<html><body><h1>Hello, ResponseBody!</h1></body></html>";
}
// 이미지 base64 인식
//	@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
// mp4 base64 인식
//	@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = "video/mp4")
// pdf base64 인식
//	@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = "application/pdf")
// base64 디코딩해 해석해 화면에 노출
@RequestMapping(value = "/base64", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public @ResponseBody byte[] base64(HttpServletRequest request, HttpServletResponse response) throws Exception {

    String uri = "http://localhost:8080/getBase64";
    String encodeBase64 = callGetMethod(uri);

    byte decode[] = Base64.decodeBase64(encodeBase64);

    return decode;
}

리턴 종류 - String (responseBody)

  • jsp 페이지가 아닌 해당 문자열을 화면에 보여줍니다. (HTML 태그를 인식하고 JSON으로 데이터를 보낼 때 사용)
  • [JSON으로 데이터 보낼시 return type은 HashMap 입니다.]

 

 

📝 @RequestParam

@RequestMapping(value = "/param.do", method = RequestMethod.GET)
public void param(@RequestParam String name, String age,
    HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

    // 호출 URI : param.do?name=lee&age=20 // name 필수 입력
    System.out.println(">>> " + name);    // >>> lee
    System.out.println(">>> " + age);    // >>> 20


}

RequestParam은 무조건 해당 이름의 키로 받아야 한다는 강제성을 부여한다.

 

 

@ResponseBody
@GetMapping(value = "/test")
public String requestParamDefault(
        @RequestParam(required = true, defaultValue = "guest") String username,
        @RequestParam(required = false, defaultValue = "-1") int age) {
    log.info("username={}, age={}", username, age);
    return "ok";
}

옵션을 통해 Default값이나 required를 조작할 수 있다

 

📝 @ModelAttribute

@RequestMapping(value = "/model.do", method = RequestMethod.GET)
public void body4(@ModelAttribute BodyVO bodyVO,
    HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

    // 호출 URI : model.do?name=lee&age=20
    // @ModelAttribute 사용시에는 해당 클래스의 객체를 생성하고 값을 set 해준다. 
    // (default로 @ModelAttribute 안 적어도 @ModelAttribute 적은 거 처럼 동작)
    // 객체를 받는 경우는 무조건 쿼리스트링으로만 동작함 (body 인식 못 함)

    System.out.println(">>> " + bodyVO.getName());     // >>> lee
    System.out.println(">>> " + bodyVO.getAge());    // >>> 20

}

사용시 해당 클래스의 객체를 생성하고 값을 set 해준다. (default로 @ModelAttribute 안 적어도 @ModelAttribute 적은 거 처럼 동작)

객체를 받는 경우는 무조건 쿼리스트링으로만 동작함 (body 내용은 자동 DI 못 함)

 

 

📝 @ResponseBody, @RequestBody

@RequestMapping(value = "/urlencoded.do", method = RequestMethod.POST)
public void urlencoded(String code,String name) {

    // 호출 Url      : urlencoded.do?name=Lee
    // Content-Type : application/x-www-form-urlencoded
    // Body 		:  key → code, Value → ABC 
    System.out.println(">>> " + code); // ABC
    System.out.println(">>> " + name); // Lee 

    // 일반적으로 POST 방식에 쿼리스트링을 붙히지 않지만 붙혀도 인식이 가능함
    // x-www-form-urlencoded 의 경우 쿼리스트링처럼 code=ABC 인식을 한다.

}


/** application/x-www-form-urlencoded **/
@RequestMapping(value = "/urlencodedToObject.do", method = RequestMethod.POST)
public void urlencodedToObject(BodyVO bodyVO) {

    // 호출 Url      : urlencoded.do?name=Lee
    // Content-Type : application/x-www-form-urlencoded
    // Body 		:  key → code, Value → ABC 
    System.out.println(">>> " + bodyVO.getName()); // ABC
    System.out.println(">>> " + bodyVO.getAge()); // ABC


}
/** application/x-www-form-urlencoded의 GET의 경우 따로 RequestBody가 필요없다. **/

/** text **/
@RequestMapping(value = "/text.do", method = RequestMethod.POST)
public void text(@RequestBody String bodyContents) {

    // 호출 Url      : text.do
    // body 		: this is text
    // Content-Type : text 또는 text/html
    System.out.println(">>> " + bodyContents); // this is text

}


/** application/json **/
@RequestMapping(value = "/json.do", method = RequestMethod.POST)
public void json(@RequestBody String bodyContents) {

    // 호출 Url      : json.do
    // body 		: {"content" : "this is json"}
    // Content-Type : application/json
    System.out.println(">>> " + bodyContents); // {"content" : "this is json"}

}

/** application/json (Object Injection) **/
@RequestMapping(value = "/jsonToObject.do", method = RequestMethod.POST)
public @ResponseBody HashMap<String, Object> jsonToObject(@RequestBody BodyVO bodyVO) {

    /** BodyVO (HashMap도 또한 Object이기 떄문에 동일하게 적용 된다. **/
    // String name
    // String age → int 형으로 값을 보내면 못 자동 Injection이 안 된다. "age" : 20 (X)

    /** 참고로 BodyVO에 default값이 설정되어 있어도 ReuqestBody에 넘어온 값이 없다면(body에 json을 안 보내면) null로 덮어씌워진다. **/
    /** 필요사항에서는 데이터를 까서 검증하는 작업을 직접해야할 거 같다. **/


    // 호출 Url      : jsonToObject.do
    // body 		: {"name" : "lee", "age":"20"}
    // Content-Type : application/json
    System.out.println(">>> " + bodyVO.getName()); // lee
    System.out.println(">>> " + bodyVO.getAge()); // 20

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("bodyVO", bodyVO);

    return map;

}
/** responseBody란 처리한 결과를 클라이언트에게 다시 돌려줘서 읽을 수 있게한다. (즉 return 값이 있어야한다.) **/
// 미사용시 → 404 페이지를 찾을 수 없음
// 사용시 → {"bodyVO" : {"name" : "lee", "age":"20"}}

/**
 * jsonToObject.do을 사용하기 위해서는 하기 라이브러리가 필요 (body 내용을 Object에 Injeciton)
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.3</version>
</dependency>

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>
**/

 

@RequestMapping(value = "/deleteIndex", method = RequestMethod.GET)
@ResponseBody
public void deleteIndex(@RequestParam(value="No[]") ArrayList indexParams, HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    // http://localhost:8080/deleteIndex?No=keyword_index2
    ArrayList<String> indexNames = new ArrayList<String>();

    indexNames = indexParams;
    IndexInfo indexInfo = new IndexInfo();
    indexInfo.deleteIndex(indexNames);
}


<script>
	$(function() {
		$("#index_delete_btn").on("click", function() {

			var checked = [];
			$("input[name='No']:checked").each(function(i) {
				checked.push($(this).val());
			});

			$.ajax({
				type : "GET",
				url : "deleteIndex",
				data : {
					No : checked
				},
				success : function(data) {
					location.reload();
				}
              		error : function()
			}); // ajax 종료
		});
	});
</script>

<tbody id="indexVOs">
    <c:forEach var="indexVO" items="${indexVOs}" begin="0"
        end="${fn:length(indexVOs)}" step="1" varStatus="status">
        <tr>
            <td>${status.count}</td>
            <td>
                <input class="form-check-input" type="checkbox"
                    value=${indexVO.name } id="flexCheckChecked" name="No"></td>
            <td>${indexVO.status}</td>
            <td><a href="/indexDetail?name=${indexVO.name}&status=${indexVO.status}
                &docsCount=${indexVO.docsCount}&storeSize=${indexVO.storeSize}">${indexVO.name}</a></td>
            <td>${indexVO.docsCount}</td>
            <td>${indexVO.storeSize}</td>
        </tr>
    </c:forEach> 
</tbody>

 

RequestBody

  • RequestBody는 HTTP Body안에 JSON을 VO에 맵핑하는 스프링 어노테이션. 

 

ReponseBody

  • ResponseBody는 사용자가 읽을 수 있게 return 해준다. (outputStream으로 현재 화면에 flush하는 것과 같은 동작)

 

 

📝 @PathVariable (동적 URL 매핑)

// PathVariable에 userId에 값이 GetMapping에 {userId}에 들어간다

@GetMapping("/mapping/{userId}")
  public String mappingPath(@PathVariable("userId") String data) {
    log.info("mappingPath userId={}", data);
    return "ok";
}

// 2개도 사용 가능
@GetMapping("/mapping/{userId}/test/{orderNo}")
    public String mappingPath(@PathVariable("userId") String data, @PathVariable("orderNo") String data2) {
      log.info("mappingPath userId={}, orderNo={}", data, data2);
      return "ok";
  }

 

 

📝 @RequestHeader, @CookieValue

@GetMapping("/headers")
        public String headers(HttpServletRequest request,
                              HttpServletResponse response,
                              HttpMethod httpMethod,
                              Locale locale,
                              @RequestHeader MultiValueMap<String, String> headerMap,
                              @RequestHeader("host") String host,
                              @CookieValue(value = "myCookie", required = false) String cookie)
        {

            log.info("request={}", request);
            log.info("response={}", response);
            log.info("httpMethod={}", httpMethod);
            log.info("locale={}", locale);
            log.info("headerMap={}", headerMap);
            log.info("header host={}", host);
            log.info("myCookie={}", cookie);
            return "ok";
        }

 

 

📝@Slf4j (롬복 필요) , @RestController

package hello.springmvc;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController // @ResponseBody 역할
public class LogTestController {

    @GetMapping(value = "")
    public void testLog(){
        String helloWorld = "hello world";
        log.info("programming start : {}",helloWorld);
    }

}

Slf4j

  • 로깅하는데 도움을 줍니다.

 

RestController 

  • Controller + ResponseBody 역할을 합니다.

 

반응형
반응형
package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.Order;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AutoAppConfigTest {

    private final String packageName = "hello.core";
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

    @Test
    @DisplayName("빈 설정 메타정보 확인")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for(String beanDefinitionName : beanDefinitionNames){
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION && beanDefinition.toString().contains(packageName) == true) {
                System.out.println("beanDefinitionName = " + beanDefinitionName + " beanDefinition = " + beanDefinition);
            }
        }
    }
}

기본적으로 생성되는 Bean + 내가 만든 Bean = 전체 Bean 정보 

전체 Bean 정보에서 해당 Bean Class 정보가 내 패키지에서 만들어진 것인지 체크해서 보여준다)

반응형
반응형
import java.io.IOException;

import org.springframework.core.io.ClassPathResource;

public class test {

	public static void main(String[] args) throws IOException {

		ClassPathResource resource = new ClassPathResource("properties.ini");

		System.out.println("resource.getFile() : " + resource.getFile());
		System.out.println("resource.getFilename() : " + resource.getFilename());
		System.out.println("resource.getInputStream() : " + resource.getInputStream());
		System.out.println("resource.getPath() : " + resource.getPath());
		System.out.println("resource.getURL() : " + resource.getURL());
		System.out.println("resource.getURI() : " + resource.getURI());

		/**
		 * 
		 	resource.getFile() : F:\project\normal_spring_project\workspace\sample\target\classes\properties.ini
		 	resource.getFilename() : properties.ini
			resource.getInputStream() : java.io.BufferedInputStream@5ebec15
			resource.getPath() : properties.ini
			resource.getURL()) : file:/F:/project/normal_spring_project/workspace/sample/target/classes/properties.ini
			resource.getURI() : file:/F:/project/normal_spring_project/workspace/sample/target/classes/properties.ini
		 * 
		 */
		
	}

}

Spring에서 쉽게 가져올 수 있도록 제공해주는 라이브러리[ClassPathResource]로 쉽게 가져올 수 있습니다

가져올 경로는 src/main/resources가 기본 경로입니다

 

🔗참고 및 출처 

http://june0313.github.io/2018/08/11/read-resource-file-on-spring/

 

반응형