오늘도 스프링 정진중.. 코드를 일일히 치는건 줄었지만 그 대신 각 어노테이션들의 기능을 알아야 제대로 사용할 수 있기 때문에 외워야 할 게 많다.
그리고 의존을 추가하면 항상 Maven Update 버튼을 눌러주자 !
Data Validation (데이터 유효성 검사)
WebDataBinder
간단히 보면 유효성감사를 수행하는 클래스.
주로 Form 데이터를 처리하고 모델 객체에 바인딩하는데 사용한다.
스프링의 바인더는 기본적으로 String 형태로 받은 다음 자기가 알아서 형변환을 해서 처리해서 돌려줌
여기서 사용하는 어노테이션들을 알아보자 !
InitBinder
- 해당 Controller로 들어오는 요청에 대해
- 추가적인 설정을 하고 싶을 때 사용할 수 있다.
- 또한 모든 요청 전에전역적으로 적용되는 초기화 작업 수행할 때 사용
- InitBinder를 선언한 메소드가 실행된다.
@ModelAttribute
- 컨트롤러 메소드의 파라미터에 사용된다.
- 해당 파라미터를 모델에 추가하고 뷰에서 사용할 수 있게함.
- form 데이터를 모델 객체에 자동으로 바인딩 할 때 사용
@Valid
- 컨트롤러 메서드 파라미터에 사용
- 해당 파라미터의 유효성 검사를 지정한다.
- 주로 모델 객체의 유효성 검사를 할 때 사용한다.
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
heibernate.validatior 클래스와 javax Validation 클래스를 의존처리를 해준다. (pom.xml !!)
Validation의 어노테이션 정리
간단하게 자주 사용할 것 같은것만 뽑아보자
@Min(value=10,message= "최소 숫자는 10이상 이어야합니다.")
@Max(value=1000,message="최대 숫자 1000임")
@NotNull(message="비어있음 현재")
private Integer id; //
@NotBlank(message="메모 입력하셈")
private String text;
@Email(message="이메일 입력하셈")
@NotBlank(message="작성자입력하셈")
private String writer;
@NotNull(message="날짜정보 입력하셈")
@DateTimeFormat(pattern="yyyy-MM-dd'T'HH:mm") //포매팅 작업이 안되면 바인더가 인식을 못한다. 형식을 제대로 인식하지 못해 오류가 발생한다.
private LocalDateTime createAt;
NotNull 과 NotBlank 와 NotEmpty 차이
- NotNull 은 말 그대로 null 만 허용하지 않아서 “” 이나 “ “ 같은 빈 문자열은 허용을 해준다.
- NotEmpty 는 null과 “” 둘 다 허용하지 않는다.
- NotBlank 는 null , “” , “ “ 모두 허용하지 않게 한다.
- 가장 강도가 높은 Validation 이다.
@InitBinder
public void dataBinder(WebDataBinder webDataBinder) {
log.info("MEMOContorller's dataBinder " + webDataBinder);
webDataBinder.registerCustomEditor(LocalDate.class, "dateTest", new DateTestEditor()); //dateTest 라는 name 의 파라미터값을 LocalDate 타입으로 바꿔준다
}// LocalDate 에 대한 커스텀데이터를 등록한다.
//dateTest 파라미터를 LocalDate 타입으로 변환한다.
@WebDatabinder : 사용자 입력데이터를 메서드 파라미터로 변환하는데 사용
private static class DateTestEditor extends PropertyEditorSupport{ //내부에서 사용할 class 선언
@Override
public void setAsText(String dateTest) throws IllegalArgumentException {
// TODO Auto-generated method stub
log.info("dateTestEditor's setAsText invoke "+dateTest);
if(dateTest.isEmpty()) { //dateTest 객체가 비어있을 경우 현재 시간으로 설정
dateTest=LocalDate.now().toString();
}else {
dateTest = dateTest.replaceAll("#", "-"); //# 문자를 - 로 바꾼다
log.info("dateTest # -> :" + dateTest);
}
LocalDate date = LocalDate.parse(dateTest,DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// log.info("parsed date : " + date);
setValue(date);
} //LocalDate 자료형을 2015-05-18 같은 데이터로 변환
//변환후에 dto 에 date 를 할당시켜준다
ExceptionHandler
서블릿에서 하던 예외처리를 스프링에서 약간의 설정만 있으면 알아서 해줌
특정 컨트롤러 내에서 예외 처리를 담당
controller 메서드에서 반환자료형을 String으로 하는 이유는 jsp 파일이 String 형태라서 그럼
이 때 이것은 포워딩 처리임.
@ExceptionHandler 라는 어노테이션을 사용한다.
ExceptionHandler 는 여러개를 만들어서 처리할 수 있는데
각 예외에 관한 핸들러는 만들어서 처리할 수 있고,
아니면 Exception 으로 해서 모든예외에 관한 핸들러를 만들어 사용할 수있다.
하지만 나중에 실제 개발을 할때는 하나의 핸들러보다는 각각의 세세한 핸들러를 만들어 사용하는게 좋다.
어떤 예외가 발생하는지 알기 좋기 때문이기도 하고
DataSource
DB연결 정보를 저장하고 Connection 을 생성하고 커넥션 풀에 등록하고 관리하는 역할을 하는 것이 DataSource 이다.
간단히 생각해서 DB Connection 을 관리하는 인터페이스이다.
히카리CP를 사용하거나 apache common DBCP 를 사용해서 DataSource를 관리한다.
@Bean
public DataSource dataSource2() {
// DriverManagerDataSource dataSource = new DriverManagerDataSource();
BasicDataSource dataSource = new BasicDataSource(); //커넥션 pooling 처리
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/bookdb");
dataSource.setUsername("root");
dataSource.setPassword("1234");
dataSource.setMaxTotal(10); //최대 연결 개수
dataSource.setMaxIdle(8); //최대 유휴 연결개수
dataSource.setInitialSize(5); //초기 연결 개수
dataSource.setMinIdle(3); //최소 유휴 연결 개수
dataSource.setMaxWaitMillis(30000); //CP에서 Connection 객체를 가져오기 위해 기다리는 최대시간
return dataSource;
}
Apache Common 을 사용한 DataSource Bean 생성
MyBatis 를 들어가기전..
Mapper와 ORM 의 차이에 대해서 알아보자.
Mapper
SQL 중심의 데이터 매핑 방식을 사용한다.
개발자가 직접 쿼리를 작성해야 한다.
장점
- 복잡한 SQL 작성 가능
- DB의 세부동작을 제어할 수 있다.
단점
- SQL 작성을 일일히 해야되서 번거롭다
- DB에 강하게 결합되어서 유지보수가 힘들어질 수 있다.
- 테이블과 객체에서 연결이 잘 안되거나 하면 일일히 내가 오류를 해결해야 한다.
ORM
객체와 DB 간의 자동 매핑을 해준다.
SQL을 작성하지 않고 객체를 조작해서 데이터 작업을 수행한다.
ORM 프레임워크가 객체와 DB 테이블 매핑을 자동으로 해준다.
장점
- SQL 작성을 거의안함
- DB 독립성 제공
- 객체 지향 개발 방식과 일관성을 유지할 수 있다.
단점
- 복잡한 쿼리 작성이 힘들다
- 성능 최적화가 어렵다
- 배울 때 힘들다.. !!
배우기 힘든건 나한테는 이거나 저거나 똑같다 ㅋㅋ
Mybatis
자바 개발자들이 데이터베이스를 쉽게 다룰 수 있도록 하는 SQL Mapper 프레임워크이다.
Maven Repository 에서 mybatis 를 받아서 의존 추가한다.
우선 Mybatis의 기본 설정을 보자.
package com.example.ex01.config;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
@Configuration
public class MybatisConfig {
@Autowired
private DataSource dataSource3; //DataSource 객체를 자동 주입한다. DataSource는 DB 연결정보를포함한 DB 데이터 소스이다
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource3);
//xml경로 설정
//MemoMapper xml 파일 위치 지정
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:mapper/*.xml");
sessionFactory.setMapperLocations(resources);
return sessionFactory.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
return new SqlSessionTemplate( sqlSessionFactory());
}
}
SqlSessionFactory
DB와의 연결과 SQL 실행에 대한 모든것을 가진 중요한 객체.
이 객체가 DataSource를 참조해서 Mybatis와 Mysql 서버를 연결시켜준다.
SqlSession을 구현하고 코드에서 대체하는 역할을 한다.
사용하기 위해서는 설정을 먼저 해주어야 한다.
root-context.xml 으로 가서 Namespaces 에 mybatis-spring 체크.
체크하고나서 다시 source 탭으로 가면
체크한 것들이 소스에 자동입력이 된다.
mybatis-config.xml 파일 추가
myBatis 는 프레임워크로 별도의 설정 파일을 가질 수 있다.
여기서의 설정은 스프링의 설정과 별도로 사용하는 모든 myBatis 설정기능을 활용한다.
(※ 우리 수업에는 딱히 이 파일은 추가하지 않았다. 왜냐면 hikariCP로 datasource 정보를 다 거기서 처리해서 그런가 DB정보를 명시하지 않았다.)
src/main/resources 에 mybatis-config.xml 파일을 추가해준다.(xml파일명은 크게 중요하지 않은듯. 알아볼 수 있게)
→ mapper.xml : 해당 SQL 문을 작성하는 xml 문서
mapper.xml
해당 SQL문을 작성하는 XMl 문서
<?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">
<mapper namespace=""> //여기는 <mapper namespace="com.example.ex01.domain.mapper.MemoMapper">
</mapper> //같이 제대로 된 주소를 매핑해야 sql연동이 가능해진다.
설정은 여기까지 하면 될것 같다.
mybatis 사용법
CRUD 함수를 만들 Mapper 파일을 인식 시키려면 @Mapper 어노테이션을 붙여주면
xml파일과 연결되어서 DB에 쿼리를 날리는 역할을 수행한다.
Mapper 파일에서 쿼리 정의
package com.example.ex01.domain.mapper;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectKey;
import org.apache.ibatis.annotations.Update;
import com.example.ex01.domain.dto.MemoDto;
@Mapper
public interface MemoMapper {
//어노테이션을 이용한 Mapping
@SelectKey(statement = "select max(id) from tbl_memo",keyProperty= "id",before=false,resultType=int.class)
@Insert(value = "insert into tbl_memo values(null,#{text},#{writer},now())" )
public int Insert(MemoDto memoDto);
@Update(value = "update tbl_memo set text=#{text} , writer=#{writer} where id=#{id}")
public int update(MemoDto memoDto);
@Delete(value = "delete from tbl_memo where id = #{id}")
public int delete(int id);
@Select(value = "select * from tbl_memo where id = #{id}")
public MemoDto select(@Param("id") int id); //만약 참조변수명이 컬럼명과 다를경우 param 으로 컬럼명이 이거다 하고 지정해준다
@Select(value = "select * from tbl_memo")
public List<MemoDto> selectAll();
@Results(id="MemoResultMap",value= {
@Result(property = "id",column = "id"),
@Result(property = "text",column="text"),
})
@Select(value = "select id,text from tbl_memo")
public List<Map<String,Object>> selectAllByResultMap();
//Xml 을 이용한 Mapping
public int insert_xml(MemoDto memoDto);
}
이렇게 각종 쿼리문을 적고 어노테이션으로 어떤CRUD 작업인지 정의한다.
@SelectKey(statement = "select max(id) from tbl_memo",keyProperty= "id",before=false,resultType=int.class)
이 부분은 특정 값을 서브쿼리로 조회하고 매핑된 객체또는 SQL 의 파라미터에 설정한다.
before=true or false : 이 서브쿼리가 SQL쿼리가 실행 전에 할지 후에 실행할지 정한다.
true라면 실행 전에 , false 라면 실행 후에 실행되게된다.
resultType : 이 서브쿼리가 반환하는 값의 타입을 지정한다.
그리고 Dao에서 CRUD 함수를 만들어 매핑시킨다.
@Autowired
private SqlSession sqlSession;
private static String namespace = "com.example.ex01.domain.mapper.MemoMapper";
public int insert(MemoDto memoDto) {
return sqlSession.insert(namespace + "Insert",memoDto);
}
SqlSession객체를 얻어 MemoMapper를 찾아 매핑시키는데 저기서 Insert는 여기서의 insert가 아니라 mapper 설정파일에서의 Insert 이다.(앞글자가 대문자)
<?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"> <!-- 마이바티스 독타입 매퍼 -->
<mapper namespace="com.example.ex01.domain.mapper.MemoMapper">
<insert id="insert_xml"
parameterType="com.example.ex01.domain.dto.MemoDto"> <!-- memoDto 를 파라미터로 지정 -->
insert into tbl_memo values(null,#{text},#{writer},now())
</insert>
<update id="update_xml"
parameterType="com.example.ex01.domain.dto.MemoDto">
update tbl_memo set text=#{text} , writer=#{writer} where id=#{id}
</update>
<delete id="delete_xml"
parameterType="com.example.ex01.domain.dto.MemoDto">
delete from tbl_memo where id=#{id}
</delete>
<select id="select_xml" parameterType="int"
resultType="com.example.ex01.domain.dto.MemoDto"> <!-- 결과값을 memoDto로 지정 -->
select * from tbl_memo where id=#{id}
</select>
<select id="SelectAll_xml_1" resultType="com.example.ex01.domain.dto.MemoDto">
select * from tbl_memo
</select>
<!-- <select id="selectAll_xml_2" ?="com.example.ex01.domain.dto.MemoDto">
select * from tbl_memo </select> -->
<!-- 여기서 함수를 선언 -->
</mapper>
mybatis의 또 다른 사용법인 xml에서 매핑을 하는 방식이다.
두 방식의 차이점
xml파일 방식
- xml파일 쪽이 더 가독성이 좋기 때문에 복잡한 쿼리에 유리하다
- 비즈니스 로직과 SQL 쿼리를 명확히 분리하여 유지보수성을 높인다.
- SQL변경시 코드 수정없이 XML 파일만 수정하면 된다.
Mapper파일 방식(인터페이스)
- 간결한 쿼리일 때 유리하다.
- SQL과 메서드가 한곳에 있기 때문에 파일 관리가 쉬움
- 조건문 , 반복문 등을 사용해야 할 경우에는 xml 보다 불편함
- java코드와 sql이 함께 있기 때문에 SQL 변경시 자바 파일을 무조건 건드리게 된다.
후반으로 가면 갈수록 xml 파일 방식이 더 나을것 같다.
혼합해서 사용도 가능하다고 함!
간단한 쿼리는 어노테이션으로 처리하고 복잡하거나 재사용이 필요한 SQL 은 xml파일 방식으로 선택을 무조건 해야한다,
'Developer Note > 국비과정 수업내용 정리&저장' 카테고리의 다른 글
24년 11월 14일 (0) | 2024.11.24 |
---|---|
24년 11월 13일 (0) | 2024.11.24 |
24년 11월 11일 (1) | 2024.11.21 |
24년 11월 08일 (2) | 2024.11.21 |
24년 11월 06일 (0) | 2024.11.20 |