어노테이션은 클래스 선언 바로 앞/필드 선언 바로 앞에 붙여준다.
@ToString
toString() 메소드를 자동으로 생성해준다.
exclude : 특정 필드를 toString() 결과에서 제외시킨다.
@ToString(exclude = "pw")
public class User {
private Long id;
private String name;
private String pw;
private int age;
}
User user = new User();
user.setId(1L);
user.setName("user");
user.setPw("1234");
user.setAge(20);
System.out.println(user);
// User(id=1, name=user, age=20)
@Builder
📖 참고
생성자에서 인자가 많고, 필수로 값을 받아야 할 필드와 선택적으로 받아도 되는 필드가 섞여있을 때 사용한다.
코드량이 줄어들고, 객체의 일관성을 유지할 수 있다.
@Builder
public class Person {
private final String name;
private final int age;
private final int phone;
}
다음과 같이 객체 생성 가능!
Person person = Person.builder() // 빌더어노테이션으로 생성된 빌더클래스 생성자
.name("seungjin")
.age(25)
.phone(1234)
.build();
@RequiredArgsConstructor
final인 필드만 가지고 생성자를 자동으로 만들어줌
@AllArgsConstructor
모든 필드를 가지고 생성자를 자동으로 만들어줌
final : 반드시 최초에 초기화 해야 함, 그 이후 수정 불가
@Component
Component 클래스 앞에 붙임
Bean Configuration 파일에 Bean을 따로 등록하지 않아도 사용할 수 있다.
자바 hashmap
https://coding-factory.tistory.com/556
HashMap은 내부에 '키'와 '값'을 저장하는 자료 구조를 가지고 있습니다. 사용자는 그 위치를 알 수 없고, 삽입되는 순서와 들어 있는 위치 또한 관계가 없습니다.
엔티티 클래스에 파라미터가 있는 생성자를 별도로 만들었으면, 기본생성자(파라미터가 하나도 없는 생성자 - @NoArgsConstructor로 만듦!)도 직접 만들어줘야 함 - JPA, Mybatis 모두 ㅇㅇ
@AllArgsConstructor(access = AccessLevel.PRIVATE) 이거 아마 이 생성자 쓸모없는데 있어야 해서 저렇게 굳이 접근제한 PRIVATE로 두는건가?
mybatis는 entity(vo)에 pk, fk이런거 명시를 못하네ㅠㅠ 그냥 필드명만 들어가서 불편함
코드가 필드인 경우에는 fk취급 안하는듯
컨트롤러단 매개변수, return문에서는 무조건 DTO사용(엔티티/VO 그대로 사용x)
엔티티-DTO변환을 어떤 layer에서 하는게 좋을까?
@JsonIgnore
Response에 해당 필드가 제외된다
(엔티티의)필드앞에 붙임
보통 DTO 대신 엔티티에 Response에 담지 않을 필드에 붙여서 사용하는듯
근데 하나의 엔티티가 여러군데에서 쓰이고, 어떨때는 이 필드가 사용될때도, 안사용될때도 있으니 복잡해지므로, DTO를 따로 파는 것이 좋고, JsonIgnore은 지양됨.
근데 dto에도 쓰네..? 뭐지
Spring Data Repository Interface에서 CRUD 기본 메소드 제공
https://escapefromcoding.tistory.com/377
find, update, delete, existsById등..
이 외에 직접 커스텀한 메소드들을 선언하려면 resources>mapper>레포지토리클래스 이름.xml
에 따로 쿼리문을 정의해두면 됨 ex.PointDao.xml
@Data
아래 어노테이션들을 포함
@ToString
@EqualsAndHashCode
@Getter
: 모든 필드@Setter
: 정적 필드가 아닌 모든 필드@RequiredArgsConstructor
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--이 메소드들이 선언된 DAO 위치-->
<mapper namespace="com.example.CinemaSeoulCopy.dao.user.PointDao">
<!--[포인트 입력]-->
<insert id="updatePoint" parameterType="PointVo">
INSERT INTO POINT (POIN_ID, USER_ID, POIN_AMOUNT, POIN_TYPE_CODE, MESSAGE)
VALUES (SEQ_POINT.NEXTVAL, #{user_id}, #{poin_amount}, #{poin_type_code}, #{message})
</insert>
</mapper>
<insert id="updatePoint" parameterType="PointVo">
INSERT INTO POINT (POIN_ID, USER_ID, POIN_AMOUNT, POIN_TYPE_CODE, MESSAGE)
VALUES (SEQ_POINT.NEXTVAL, #{user_id}, #{poin_amount}, #{poin_type_code}, #{message})
</insert>
<insert>
: CRUD중 C#{파라미터의 필드명}
= 해당 필드명의 값을 불러옴 <!--[포인트 조회]-->
<select id="getPoint" parameterType="Integer" resultType="UsersVo">
SELECT USER_ID, USER_NAME, CURR_POINT, ACCU_POINT
FROM USERS
WHERE U.USER_ID = {user_id}
</select>
현재 포인트 실제 ( ) 존재 와 누적 포인트 사용을 ( 포함하여 누적된 모든 포인트 로)
<![CDATA[ ]]>
이렇게 선언하고 안에 문자열을 채워 넣으면 , [ ]
안에 있는 문장은 파싱되지 않고 그대로 문자열로 출력된다.
마이바티스에서 매퍼 파일은 XML으로 작성되어 있고, 파싱될 때 XML 표준으로 파싱된다.
SELECT문에는 조건을 걸어 쿼리하기 위해 <, >, = 등의 기호를 많이 사용하는데, 이것이 파싱 중에 태그로 인식되거나 하는 등의 문제가 생길 수 있다.
<![CDATA[ ]]>
안에 원하는 쿼리문을 선언 한다면, 파싱하지 않고 그대로 문자열로 인식 시킬 수 있어 이런 문제를 예방할 수 있다.
동적 SQL에서는 사용하지 못하는데, 필요한 특수문자에 한해서만 적용시키면 동적 SQL에서도 사용 가능하다.
TO_CHAR
날짜 등을 문자열로 변환하는 함수
https://gent.tistory.com/331
SELECT TO_CHAR(SYSDATE, 'YYYYMMDD') --20200723
, TO_CHAR(SYSDATE, 'YYYY/MM/DD') --2020/07/23
, TO_CHAR(SYSDATE, 'YYYY-MM-DD') --2020-07-23
, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') --2020-07-23 11:10:52
FROM dual
https://java119.tistory.com/42
<if test="조건문">
조건문이 참이면 실행할 쿼리문 일부
</if>
조건문은 테이블의 필드명이 아닌 파라미터의 필드가 들어감
형태도 그냥 java 형태
<select id="findPoint" resultType="PointInfoDto">
SELECT P.POIN_ID, P.POIN_AMOUNT, (SELECT CODE_NAME FROM CODE C WHERE C.CODE_ID = P.POIN_TYPE_CODE) AS POIN_TYPE,
P.MESSAGE, P.POIN_DATETIME
FROM POINT P
WHERE P.USER_ID = #{user_id}
<if test="start_date != null"><![CDATA[
AND #{start_date} <= TO_CHAR(POIN_DATETIME, 'YYYYMMDD')
]]></if>
</select>
dao.xml에서 왜 어떤건 parameterType 적고 어떤건 안적지?
근데 인터넷에서는 파라미터 여러개 쓰려면 Vo로 엮거나 맵 쓰라는데..?
음.. 그냥 parameterType을 안써버리면 문제 없는건가? 대신 타입검사는 안해줄것같기도 하고
대신 쓸거면 dao.java파일의 메소드의 파라미터 타입과 parameterType을 완전히 맞춰야 함
맵(해쉬맵) 쓰는 방법 : https://codevang.tistory.com/276
https://popo015.tistory.com/100
SQL 수행작업 중 insert된 이후에 알 수 있는 값 또는,
생성된 값을 바로 가져와서 select 쿼리를 보내야 하는 경우가 있다.
주로 생성하고 난 후의 인덱스(번호)를 가져와 작업해야 하는 상황에서 많이 사용한다.
이런경우 java에서 insert 쿼리를 실행하고 값을 받은 후
값을 가지고 다시 쿼리를 DB에 전송하는 방법이 있다.
하지만, 불필요한 여러번의 DB 입출력은 시간이 느려진다는 단점이 있다.
그때, selectKey를 사용하여 바로 적용할 수 있다.
마이바티스, 아이바티스 두개 다 적용이 가능하다.
selectKey는 DB에 명령을 한번만 보내며, 우선 입력한 값의 결과값을 다음 쿼리로 바로 return 시켜주는 것이다.
https://goddaehee.tistory.com/92
사용자가 함수(계산)를 실행할 때 임시로 사용하는데 적합하다.
SELECT SEQ_USERS.nextval FROM DUAL
ex) SELECT 시퀀스.NEXTVAL FROM DUAL;
ex) SELECT SYSDATE FROM DUAL;
ex) SELECT CURRENT_DATE FROM DUAL;
ex) Merge into 내부에서 사용
https://mine-it-record.tistory.com/61
NEXTVAL, CURRVAL
https://mine-it-record.tistory.com/62
testSeq가 시퀀스라고 할 때
-- 해당 시퀀스의 값을 증가시키고 싶다면
testSeq.NEXTVAL
-- 현재 시퀀스를 알고 싶다면
testSeq.CURRVAL
AS
생략(SELECT CODE_NAME FROM CODE C WHERE C.CODE_ID = USERS.USER_TYPE_CODE) USER_TYPE
USER_TYPE 앞에 AS 생략되어있음. 생략 가능!
CODE_ID가 곧 코드
@Transactional
https://pjh3749.tistory.com/269
클래스 또는 메소드 정의 앞에 붙임
@Transactional(readOnly = true)
: 데이터 변경 없이 조회만 하는 기능이 많을 경우에 클래스 이름 앞에 붙이기 -> 성능 up@Transactional(rollbackFor = {이 예외가 발생했을때 롤백해야하는 예외.class}
@Transactional(rollbackFor = {CheckedException.class}
@Transactional(rollbackFor = {Exception.class}
@Transactional(rollbackFor = {RuntimeException.class, Error.class}
insert, update, delete에는 resultType이 없고
row의 개수를 반환한다.
insert의 경우는 삽입된 행의 개수를 반환
update의 경우는 수정에 성공한 행의 개수를 반환(실패시 0 반환)
delete의 경우는 삭제한 행의 개수를 반환
따로 exception 패키지를 파서 ExceptionController, custom exception 클래스들을 정의하기
ExceptionController
Controller 단에서 발생하는 예외들을 어떻게 처리할지 정의
원래는 예외가 발생할 때마다 try catch 문으로 일일이 예외 처리를 해줘야 하는데, 여기에 정의된 예외는 controller에서 발생하면 자동으로 처리해줌
servcie 단에서 발생한 예외도 controller의 함수를 호출하기만 하면 exceptionController가 처리해줌
@ControllerAdvice
@Slf4j
public class ExceptionController {
//401
//DuplicateException이 발생하면 메소드에 정의된 대로 처리 : 401 Unauthorized 에러를 발생시킴
@ExceptionHandler({DuplicateException.class})
public ResponseEntity<?> UnAuthorizedException(final DuplicateException ex){
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ex.getMessage());
}
}
custom exception
//이 예외가 발생하면 BAD_REQUEST 응답을 반환
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class WrongArgException extends RuntimeException{
//private static final String MESSAGE = "메세지"; //발생할 메세지 일률적으로 처리 가능
//이 응답을 발생시킬 생성자
//throw new WrongArgException("에러메세지"); 형식으로 에러 발생시킴
public WrongArgException(String message) {
super(message);
}
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
: 응답의 상태 코드를 지정
예외는, 예외가 발생할 수 있는 메소드 정의시에 thorws Exception
붙이고, throw new WrongArgException("message...");
이런 식으로 발생시킴
참고할 블로그 : https://bloowhale.tistory.com/72 , https://kdg-is.tistory.com/221?category=983893
생성메소드(createOrder), 비즈니스로직(주문취소 등), 조회로직(전체주문가격조회) 은 해당 엔티티(VO) 클래스에 넣자
https://velog.io/@vgo_dongv/Spring-%EC%9D%BC%EB%8C%80%EB%8B%A4-%EA%B4%80%EA%B3%84
계층형 데이터구조
https://velog.io/@joyfuljoyful/MyBatis-%EB%8F%99%EC%A0%81%EC%BF%BC%EB%A6%AC-trimwhereset
필터링/키워드 검색기능 구현시 많이 사용
(조건에 따라 쿼리문을 다르게 하는 경우)
<trim>
문에 의해 생성되는 SQL 구문 앞에 추가적인 구문을 넣어줍니다.<trim>
문에 의해 생성되는 SQL 구문 앞에 해당 문자가 있으면 자동으로 지워줍니다.SELECT * FROM board WHERE
https://velog.io/@joyfuljoyful/MyBatis-if
if와 달리 choose는 여러 상황들 중 하나의 상황에서만 동작합니다.
Java의 'if~else'와 유사하다.
<otherwise>
는 위의 모든 조건이 만족되지 않을 경우에 사용합니다.
<choose>
<when test="type == 'T'.toString()">
(title like '%'||#{keyword}||'%')
</when>
<when test="type == 'C'.toString()">
(content like '%'||#{keyword}||'%')
</when>
<when test="type == 'W'.toString()">
(writer like '%'||#{keyword}||'%')
</when>
<otherwise>
(title like '%'||#{keyword}||'%' OR content like '%'||#{keyword}||'#')
</otherwise>
</choose>
WHERE 절 내에서 특정값 여러개를 선택하는 SQL 연산자
괄호 내의 값 중 일치하는 것이 있으면 TRUE
SELECT * FROM 테이블명
WHERE 컬럼명 IN (값1, 값2, ...);
https://java119.tistory.com/85
collection : 전달받은 인자. List or Array 형태만 가능
item : 전달받은 인자 값을 alias 명으로 대체
open : 구문이 시작될때 삽입할 문자열
close : 구문이 종료될때 삽입할 문자열
separator : 반복 되는 사이에 출력할 문자열
index : 반복되는 구문 번호이다. 0부터 순차적으로 증가
https://jhnyang.tistory.com/454
https://gent.tistory.com/401
부분을 포함하고 있는 데이터를 검색할 때
문자열 자르기
인덱스는 0부터 시작이 아닌 1부터 시작
MyBatis로 개발 시 입출력 변수의 javaType이나 jdbcType을 명시할 때 사용
ex. INTEGER(int), VARCHAR(String)
타입 표 : https://itmoon82.tistory.com/23
MapStruct은 엔티티와 DTO간의 매핑을 손쉽게 하게끔 도와준다.
-컴파일 시점에 맵핑클래스를 생성함(그래서 매우 좋음 바로바로 확인가능)
@Nullable, @NotNull
@NotNull을 변수에 붙여서 검증에 사용할 수 있다. 하지만 메소드 인자에서 이 둘은 아무런 역할도 하지 않는다. 메소드 인자에서 이 둘은 단순한 문서 작성 도구로 작용한다.
유효성 검사시 메서드 인자에는 @NotNull이 아닌 @Valid 를 사용해야한다.
메소드 인자에서 유효성 검사하기 : lombok @NonNull
롬복에서 제공하는 @NonNull은 메서드의 인자에 사용하면 null이 들어올 시 NullPointerException을 발생시킨다.