Spring
- java기반 백엔드 웹 프레임 워크
- 엔터프라이즈용 java 애플리케이션 개발을 편하게 할 수 있게 해주는 오픈소스 경량급 애플리케이션 프레임워크
- 스프링 프레임 워크의 4가지 특징, IoC, DI, AOP, POJO
IoC, 제어의 역전
- Java에서 객체를 갱성할 때 의존성을 역전시켜 제어권을 직접갖지 않는 것을 의미한다
- 스프링 컨테이너가 객체를 관리해준다
- 이해가 안가...
DI, 의존성 주입
- Field Injection, Setter Injection, Constructor Injection
- 어노테이션 @Autowired 사용
AOP, 관점 지향 프로그래밍
- 어떤 로직을 기준으로 "핵심관점", "부가관점"으로 나누어 각각 모듈화, 기능을 비즈니스 로직과 공통 모듈로 구분하고 코드 밖에서 필요한 시점에 비즈니스 로직을 삽입하여 실행되도록 함
- 여러 객체에 공통으로 적용할 수 있는 기능을 구분함으로써 재사용성을 높여주는 기법
- 공통 관심을 따로 빼내어 외부에서 접근해 사용하도록 함으로써 개발자는 핵심관점 코드에만 집중하도록 할 수 있다
POJO, 단순한 자바 오브젝트
- 다른 기술 사용없이 순수 java만을 통해 생성된 객체
- 외부 라이브러리 import해서 사용할 경우 변경 시 코드를 모두 변경하거나 재사용이 어려울 수 있음
- 객체 지향적인 원리에 충실하면서 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 의미
Spring Boot
- 쉽고 빠르게 Spring 프레임워크 사용가능
- was 내장, 독립적 실행가능
- 스프링 부트 스타터 제공
- 애플리케이션 설정을 xml이 아닌 java코드로 직관적 작성가능
- jar을 이용해 자바 옵션만으로 배포가능, 실행환경에서 별도의 설정이 필요 없음
시작하기
- https://start.spring.io/ : 스프링 프로젝트 만들어주는 사이트, 원하는 라이브러리 선택하고 생성가능
- 기본적인 수업 프로젝트 세팅, 디펜던시는 이후 build 파일에서 따로 추가할 수도 있으니 걱정 ㄴㄴ

- 생성 후 zip파일이 다운되는데 해당 파일의 압축을 풀고 내가 작업하려는 공간에 압축 해제된 파일을 넣는다. 내 경우 바탕화면의 36_spring 폴더 안에 넣음
- 해당 파일을 intelliJ에서 open하면 자동으로 build가 시작된다
- 실행은 src/main/java/내가만든파일명/SpringBootMybatisApplication.java 파일의 main함수를 실행하고 localhost:8080으로 접속해보면 된다
- Spring도 MVC 패턴을 사용하여 프로젝트를 구성

정적파일
- src/main/resources/templates에 html파일을 생성하여 controller에서 연결하여 사용할 수 있다
- controller에서 return시 기본적으로 해당위치의 폴더들로 연결됨
Thymeleaf
- 템플릿 엔진
- html 태그에 속성을 추가해 페이지에 동적으로 값을 추가하거나 처리할 수 있게 도와주는 것
- 이전의 ejs와 비슷한 느낌? html문서에 키워드로 변수 사용할 수 있도록 해줌
- 표현식: ${형태}를 가장 많이 쓴 듯

1) html태그에 코드 추가해야 사용가능
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2) 사용문법
- 기본적인 형태는 태그안에 th:~~ 형태로 작성
- 페이지 렌더 시 서버에서 받아 온 값을 보여줄 때 사용함
- th:text = innerText와 유사
<td th:text="${board.no}"></td>
- th:utext = innerHtml과 유사, html 태그 문자열도 인식
- th:value = html요소의 value값을 지정가능 button, input 등
- th:with = 변수값을 지정해서 사용 가능, 서버에서 보낸 hello 변수의 값을 temp라는 내가 생성한 변수에 넣어서 html파일에서 temp라는 변수명으로 사용가능
<div th:with="temp=${hello}" th:text="${temp}"></div>
- th:switch = switch-case문, th:case로 각 case를 구분한다, default의 경우 case = "*" 을 마지막에 사용해서 표현한다

- th:if = if문, else if는 사용이 불가능, else문은 unless라는 키워드로 대신 사용 = 뒤에 "안에 조건문을 적어 사용함" if와 unless의 조건은 동일해야함(unless는 조건이 아닌 경우를 인식하기 때문에)
- th:each = 반복문, each="지정변수:${서버에서보낸배열}" 형태를 반복하려는 태그에 넣고 그 안에서 배열 객체를 지정한 변수 이름으로 한 개씩 접근할 수 있음, for each문과 비슷한 사용 방식
Controller
- controller폴더를 만들고 그 안에 클래스를 생성한다
- 기본적으로 대문자로 시작하는 것이 관례
- 생성된 클래스에 어노테이션 @Controller를 사용하여 지정해준다
- 클래스 내부에 메소드를 생성하는데, @GetMapping 등의 어노테이션을 통해 method와 주소를 지정해서 사용할 수 있다. String으로 html 파일명을 리턴할 경우 해당 파일이 렌더링된다.(경로는 기본적으로 templates라 생략 가능, .html도 생략가능)
API
- GET
- GetMapping, parameter나 query로 데이터를 받을 수 있다
1) ?key=value받기
- @RequestParam 어노테이션 사용
- 사용예시
@GetMapping(url)
public String getMethod(@RequestParam(value="key") String key) {
return "view";
}
2) /{value받기}
- @PathVariable 사용
- url주소에 받을 변수 명시
- 사용예시
@GetMapping(url/{value})
public String getMethod(@PathVariable String value) {
return "view";
}
- POST: @PostMapping(url) 사용
- Model model: import하여 사용가능, model.addAttribute 메소드로 렌더링할 페이지에 데이터 함께 전송가능
@GetMapping("")
public String getBoard(Model model) {
List<BoardDTO> boards = boardService.getBoardList();
model.addAttribute("boards", boards);
return "board";
}
- view를 리턴하지 않고, 데이터만 전달할 때는?
- @ResponseBody 사용하기, res.send()와 유사한 개념
Axios
- html코드에 axios cdn 추가하고 axios.get or post 등의 요청 전송
- form으로 데이터 받을 경우 controller에서 @RequestBody로 변수 받기 필수!!
- 메소드 위에 @ResponseBody 어노테이션 사용하고 전달하려는 데이터 return, html에서 타임리프로 사용가능
- 예시코드
@PatchMapping("/{id}")
@ResponseBody
public Map<String, Boolean> patchBoard(@RequestBody BoardCreateDTO board, @PathVariable int id) {
Map<String, Boolean> result = new HashMap<String, Boolean>();
try{
boardService.updateBoard(id, board);
result.put("result", true);
} catch(Exception e){
log.error("patch error {}",e.getMessage());
result.put("result", false);
}
return result;
}
Controller - Rest
- Representational State Transfer
- 서버와 클라이언트 통신 방법 중 하나로, http URI를 통해 자원을 명시하고 http method를 이용해 자원을 교환하는 통신 방법
- 특징: Server-Client 구조, Stateless(무상태), Cacheable(캐시처리가능), Layered System(계층화), Uniform Interface(인터페이스 일관성)
- 장점: http 프로토콜 인프라를 그래도 사용하여 별도의 인프라 구축 필요X, http표준 프로토콜을 따르는 모든 플랫폼에서 사용 가능, 서버와 클라이언트 역할을 명확하게 분리
- 단점: http method 형태가 제한적, 구형 브라우저에서는 호환이 되지 않아 지원못해주는 동작이 많다
- dto와 vo를 컨트롤러 메소드에서 전달받는 인자의 타입으로 지정하여 사용
DTO
- Data Transfer Object
- 계층 간 데이터 교환을 위해 사용하는 객체
- 데이터를 옮기기 위한 전달자
- 다른 로직을 가지지 않는 순수한 데이터 객체
- DTO 예시(Setter필수)
@Getter
@Setter
public class UserDTO {
private int id;
private String name;
private String nickname;
private int no;
}
VO
- Value Object
- DTO와 유사하지만 read-Only속성을 가짐(setter불가)
- model.addAttribute와 사용 불가능
- DTO vs VO

Spring Database
JDBC
- java Database Connectivity
- 자바와 db를 연결해주는 통로, 자바에서 db에 접근할 수 있도록 해주는 자바 API
- Spring JDBC: 스프링 프레임 워크의 일부, db작업 단순화, 코드 양을 줄여줌
SQL mapper와 orm
- spring의 두가지 유형의 데이터베이스 상호작용 방식, 두 방식 모두 java 객체와 데이터베이스 간의 상호작용
- 차이점
1) SQL mapper
- 개발자는 sql쿼리 직접 작성, 퀴리 결과를 java 객체에 매핑함
- 동적 sql생성, 조건문, 반복문 등 sql작성에 있어서 유연
- sql쿼리의 세밀한 튜닝이 필요할 때 주로 사용
- ex) MyBatis, JDBCTemplate
2) ORM
- java객체가 데이터베이스와 어떻게 매핑 될지를 정의함
- 대부분의 crud 연산에 대한 sql을 자동으로 생성, 객체 지향적으로 데이터를 다룰 수 있게 됨
- ex) Hibernate, JPA
MyBatis
- SQL Mapper로써, JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 매핑을 대신해준다.
- JDBC의 모든 기능을 사용가능, 쉬운 접근서오가 코드의 간결함
- sql문과 프로그래밍 코드 분리
- 다양한 프로그래밍 언어로 구현 가능
1) myBatis를 사용하기 위해 dependency 추가
- build gradle 파일 수정
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
- 수정 후 아이콘 클릭하여 빌드(필수!) 후 실행
2) application.properties 수정
- 예시코드
spring.application.name=spring-boot-mybatis
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=yes&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Seoul
spring.datasource.username=root
spring.datasource.password=1234
mybatis.type.aliases-package=com.spring.boot.mapper
mybatis.mapper-locations=mybatis-mapper/*.xml
- 바꿔야 하는 부분: db username과 password, mapper-location 자기 설정대로 수정해야함
- mybatis-mapper 이하의 모든 xml 파일에 접근 가능하도록 함

프로젝트 구조와 흐름

- 실습 문제 폴더 구조, 자세한 내용은 git참고
- https://github.com/hjh3933/SeSAC_Dobong1_Web/tree/main/35_spring/spring-boot-mybatis

- 혼자 설명해보기(select)
-> sql문으로 테이블 생성하고 코드 작성 시작
-> domain폴더에 테이블과 동일한 구조의 클래스작성(Getter, Setter)
-> dto폴더에 실제로 view와 controller에서 주고 받을 형식의 클래스 작성(예를 들어 비밀번호 값은 보여주지 않는다거나, 회원가입시 인덱스 값은 전송받을 필요가 없기 때문에 domain과 달라질 수 있는 거임)
-> mapper 폴더에 사용할 테이블에 대해 인터페이스 생성, 이후 sql명령 별 메솓를 작성하고 xml파일과 매칭해서 사용함
-> controller 생성 후 메소드 작성 시작 service의 메소드를 통해 사용할 dto데이터 받음
-> service는 mapper 폴더의 인터페이스에서 추상메소드를 불러와서 sql결과를 domain형태로 받고, 해당 데이터를 dto형태로 set하는 작업을 진행, 이후 해당 dto 데이터를 return함
-> 컨트롤러는 해당 데이터를 받아 axios나 페이지를 렌더하면서 데이터를 전송함
-> sql문은 resources하위의 xml파일에 작성하는데 기본형태는 아래와 같고, id는 interface의 메소드와 동일해야함, 태그 사이에 sql문을 작성함
<?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="lecture.spring_boot_mybatis.mapper.BoardMapper">
<select id="retrieveAll" resultType="lecture.spring_boot_mybatis.domain.Board">
SELECT board.* FROM board
</select>
</mapper>
-> 값을 불러오는게 아니라 전달하는 insert, update, delete 등의 경우 로직은 비슷함 컨트롤러에서 dto 타입 전달 -> service -> interface를 거쳐 -> .xml에서 sql 작성 후 결과에 따라 값 리턴
-> xml에서 값을 받아서 sql문에 사용할 경우 parameterType 작성필요, 보통 dto나 domain은 map으로 받음, 이외에 String이나 Integer 등 참조 타입으로도 전달가능
<update id="updateBoard" parameterType="map">
UPDATE board SET title = #{title}, content = #{content}, writer = #{writer} WHERE id = #{id}
</update>