본문 바로가기

Web Development/Spring

[SpringBoot+Vue.js] 자바 스프링부트 활용 웹개발 실무용

728x90
송자바님의 [자바 스프링부트 활용 웹개발 실무용] 강의 내용을 기반으로 작성된 글입니다

Spring 초기 세팅

위의 설정으로 generate해서 서버를 실행시키면, 아래와 같이 에러가 발생하며 빌드가 되지 않는다. 

DB 환경 설정

1. src/main/java 안에 conf패키지 생성

2. conf 패키지 안에 DatabaseConf.java 클래스 생성

package conf;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DatabaseConf {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
}

3. 아래와 같이 application.properties에서 spring.datasource를 정의

Tibero 예시)

#tibero
db.type=tibero
spring.datasource.driver-class-name=com.tmax.tibero.jdbc.TbDriver
spring.datasource.url=jdbc:tibero:thin:@10.0.000.00:1521:SSID
spring.datasource.username=username
spring.datasource.password=passwrd
spring.jpa.database-platform=org.hibernate.dialect.Oracle9Dialect

MySql 예시)

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/DB명작성?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=본인 환경의 DB 유저명
spring.datasource.password=본인 환경의 DB 유저의 비밀번호

4. 각 DB driver maven dependency 추가

MySql 예시)

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

 

Domain 클래스 생성

domain 패키지 안에 Board.java 클래스 생성

package study.spring_vue.domain;

import lombok.Data;

import java.util.Date;

@Data
public class Board {

    private String title;
    private String contents;
    private Date regDate;
    private int boardSeq;
}

Repository 클래스 생성

repository 패키지 안에 BoardRepository.java 클래스 생성

package study.spring_vue.repository;

import org.springframework.stereotype.Repository;
import study.spring_vue.domain.Board;

import java.util.List;

@Repository
public interface BoardRepository {

    List<Board> getList();

    Board get(int boardSeq);

    void save(Board board);

    void update(Board board);

    void delete(int boardSeq);
}

Serivce 클래스 생성

service 패키지 안에 BoardService.java 클래스 생성

package study.spring_vue.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import study.spring_vue.domain.Board;
import study.spring_vue.repository.BoardRepository;

import java.util.List;

@Service
public class BoardService {

    @Autowired
    private BoardRepository repository;

    public List<Board> getList(){
        return repository.getList();
    }

    public Board get(int boardSeq){
        return repository.get(boardSeq);
    }

    public void save(Board board){
        repository.save(board);
    }

    public void update(Board board){
        repository.update(board);
    }

    public void delete(int boardSeq){
        repository.delete(boardSeq);
    }
}

Controller 클래스 생성

controller 패키지 안에 BoardController.java 클래스 생성

package study.spring_vue.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import study.spring_vue.domain.Board;
import study.spring_vue.service.BoardService;

import java.util.List;

@RestController
public class BoardController {

    @Autowired
    private BoardService service;

    @GetMapping
    public List<Board> getList(){
        return service.getList();
    }

    @GetMapping("/{boardSeq}")
    public Board get(@PathVariable int boardSeq){
        return service.get(boardSeq);
    }

    @PostMapping("/save")
    public void save(Board board){
        service.save(board);
    }

    @PostMapping("/delete/{boardSeq}")
    public void delete(@PathVariable int boardSeq){
        service.delete(boardSeq);
    }
}

MyBatis 설정

1. src/resources 안에 mybatis 디렉토리 생성

2. mybatis 안에 sql 디렉토리 생성

3. sql 디렉토리 안에 Board.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="study.spring_vue.repository.BoardRepository">
    <select id="getList" parameterType="study.spring_vue.domain.Board" resultType="study.spring_vue.domain.Board">
        SELECT
            BOARD_SEQ,
            TITLE,
            CONTENTS,
            REG_DATE
        FROM T_BOARD
        ORDER BY REG_DATE DESC
    </select>

    <select id="get" parameterType="int" resultType="study.spring_vue.domain.Board">
        SELECT
        BOARD_SEQ,
        TITLE,
        CONTENTS,
        REG_DATE
        FROM T_BOARD
        WHERE BOARD_SEQ = #{boardSeq}
        ORDER BY REG_DATE DESC
    </select>

    <insert id="save" parameterType="study.spring_vue.domain.Board">
        INSERT INTO T_BOARD
        (
            TITLE,
            CONTENTS,
            REG_DATE
        )
        VALUES
        (
            #{title},
            #{contents},
            NOW()
        )
    </insert>

    <update id="update" parameterType="study.spring_vue.domain.Board">
        UPDATE T_BOARD
        SET
            TITLE = #{title},
            CONTENTS = #{contents},
        WHERE BOARD_SEQ = #{boardSeq}
    </update>

    <delete id="delete" parameterType="int">
        DELETE T_BOARD
        WHERE BOARD_SEQ = #{boardSeq}
    </delete>
</mapper>

4. conf 패키지 안에 MybatisConf.java 클래스 생성

package conf;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
@MapperScan(basePackages = "study.spring_vue.repository")
public class MybatisConf {

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Autowired DataSource dataSource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/sql/*.xml"));
        SqlSessionFactory factory = factoryBean.getObject();
        factory.getConfiguration().setMapUnderscoreToCamelCase(true);
        return factoryBean.getObject();

    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(@Autowired SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

 

Springfox Swagger 사용해 API 문서 제작

1. springfox-swagger2, springfox-swagger-ui 디펜던시 추가

<properties>
	<java.version>1.8</java.version>
	<swagger.version>2.9.2</swagger.version>
</properties>

<dependency>
	<groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>${swagger.version}</version>
</dependency>

<dependency>
	<groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>${swagger.version}</version>
</dependency>

2. swaggerConfig.java 클래스 생성

package study.spring_vue.conf;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket docket() {
        ApiInfoBuilder apiInfo = new ApiInfoBuilder();
        apiInfo.title("API Server Documentation");
        apiInfo.description("Api information descriptions");

        Docket docket = new Docket(DocumentationType.SWAGGER_2);
        docket.apiInfo(apiInfo.build());

        ApiSelectorBuilder apis = docket.select().apis(RequestHandlerSelectors.basePackage("study.spring_vue.mvc.controller"));
        apis.paths(PathSelectors.ant("/**"));

        return apis.build();
    }
}

3. application.properties 파일에서 한 줄을 추가하자.

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

4. swagger-ui.html 로 이동해 작동 확인

5. controller에 @Api 어노테이션을 붙여 API로 등록

@RestController
@RequestMapping("/board")
@Api(tags = "Board API")
public class BoardController {

    @Autowired
    private BoardService service;

    @GetMapping("/list")
    @ApiOperation(value="detail", notes="lookup detailed board information")
    public List<Board> getList(){
        return service.getList();
    }

공통 Response 객체 생성

1. BaseResponseCode 생성

package study.spring_vue.conf.http;

public enum BaseResponseCode {
    SUCCESS,
    ERROR,
    DATA_IS_NULL,
    VALIDATE_REQUIRED,
    ;
}

2. BaseResponse 생성 

package study.spring_vue.conf.http;

import lombok.Data;

@Data
public class BaseResponse<T> {
    private BaseResponseCode code;
    private String message;
    private T data;

    public BaseResponse(T data) {
        this.code = BaseResponseCode.SUCCESS;
        this.data = data;
    }

}

3. Controller에서 사용 예시

@GetMapping("/{boardSeq}")
@ApiImplicitParams({
        @ApiImplicitParam(name="boardSeq", example="1")
})
public BaseResponse<Board> get(@PathVariable int boardSeq){
    return new BaseResponse<Board>(service.get(boardSeq));
}

Spring Message 다국어 설정

아래 글 참고하면 Spring 내부에서 다국어 설정하는 절차에 대해 더 자세히 알 수 있다. 

 

[Spring] Spring 어플리케이션 메시지 다국어 및 재로딩 처리

[Spring] Spring 어플리케이션 메시지 다국어 및 재로딩 처리 Spring IoC 컨테이너 = ApplicationContext가 갖고있는 기능 중 MessageSource는 국제화(i18n)와 관련된 기능을 제공해주는데 이를 이용해서 어플리..

atoz-develop.tistory.com

1. WebConfiguration 클래스 생성 및 messageSource 추가 

package study.spring_vue.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

import java.util.Locale;

@Configuration
public class WebConf {
    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
        source.setBasename("classpath:/messages/message");
        source.setDefaultEncoding("UTF-8");
        source.setCacheSeconds(60);
        source.setDefaultLocale(Locale.KOREAN);
        source.setUseCodeAsDefaultMessage(true);
        return source;
    }
}

2. resources/message 아래에 message_ko_KR.properties 작성

SUCCESS=성공했습니다.
ERROR=에러가 발생했습니다.
DATA_IS_NULL=요청하신 {0} 데이터 값은 NULL입니다.
VALIDATE_REQUIRED= {0} ({1}) 필드는 필수로 입력하셔야 합니다.

3. message 활용 예시

@PutMapping
public BaseResponse<Integer> save(BoardParameter board){
    if(ObjectUtils.isEmpty(board.getTitle())){
        throw new BaseException(BaseResponseCode.VALIDATE_REQUIRED, new String[] {"title", "제목"});
    } else if (ObjectUtils.isEmpty(board.getContents())) {
        throw new BaseException(BaseResponseCode.VALIDATE_REQUIRED, new String[] {"contents", "내용"});

    }
    service.save(board);
    return new BaseResponse<Integer>(board.getBoardSeq());
}

예외처리와 ControllerAdvice 사용법

@Controller나 @RestController에서 발생한 예외를 한 곳에서 관리하고 처리할 수 있게 도와주는 어노테이션

자세한 설명 및 활용법은 아래 글 참고

 

[Spring Boot] @ControllerAdvice을 이용한 Exception 처리

오류 처리는 프로그램을 개발하는데 있어서 매우 큰 부분을 차지한다. 오류를 예측해서 비정상적인 상황이 발생하지 않게 하는 것은 정말 중요하다. 1. @ControllerAdvice 란? @Controller나 @RestController

bamdule.tistory.com

1. conf/exception 아래에 AbstractBaseException 추상 클래스 생성

package study.spring_vue.conf.exception;

import study.spring_vue.conf.http.BaseResponseCode;

public abstract class AbstractBaseException extends RuntimeException{
    private static final long serialVersionUID = 8342235231880246631L;

    protected BaseResponseCode responseCode;
    protected Object[] args;

    public AbstractBaseException(){}

    public AbstractBaseException(BaseResponseCode responseCode) {
        this.responseCode = responseCode;
    }

    public BaseResponseCode getResponseCode(){
        return responseCode;
    }

    public Object[] getArgs() {
        return args;
    }
}

2. AbstractBaseException을 상속받은 BaseException 클래스 생성

package study.spring_vue.conf.exception;

import study.spring_vue.conf.http.BaseResponseCode;

public class BaseException extends AbstractBaseException{
    private static final long serialVersionUID = 8342235231880246631L;

    public BaseException(){

    }
    public BaseException(BaseResponseCode responseCode) {
        this.responseCode = responseCode;
    }
    public BaseException(BaseResponseCode responseCode, String[] args) {
        this.responseCode = responseCode;
        this.args = args;
    }

}

3. conf/web/bind/annotation 하위에 BaseControllerAdvice 클래스 생성

package study.spring_vue.conf.web.bind.annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import study.spring_vue.conf.exception.BaseException;
import study.spring_vue.conf.http.BaseResponse;

import java.util.Locale;

@ControllerAdvice
public class BaseControllerAdvice {

    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(value={BaseException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    private BaseResponse<?> handleBaseException(BaseException e, WebRequest request) {
        return new BaseResponse<String>(e.getResponseCode(), messageSource.getMessage(e.getResponseCode().name(), e.getArgs(), null));
    }
}

 

Interceptor 사용법

1. conf 아래에 servelt.handler 패키지 생성

2. 위 패키지 아래에 BaseHandlerInterceptor.java 클래스 생성

package study.spring_vue.conf.servlet.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class BaseHandlerInterceptor implements HandlerInterceptor {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws  Exception {
        logger.info("preHandle requestURI : {}", request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("preHandle requestURI : {}", request.getRequestURI());
    }
}

3. conf/WebConf.java 클래스를 WebMvcConfigurer를 상속받도록 수정하고 Interceptor를 등록

package study.spring_vue.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import study.spring_vue.conf.servlet.handler.BaseHandlerInterceptor;

import java.util.Locale;

@Configuration
public class WebConf implements WebMvcConfigurer {
    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
        source.setBasename("classpath:/messages/message");
        source.setDefaultEncoding("UTF-8");
        source.setCacheSeconds(60);
        source.setDefaultLocale(Locale.KOREA);
        source.setUseCodeAsDefaultMessage(true);
        return source;
    }

    @Bean
    public BaseHandlerInterceptor baseHandlerInterceptor() {
        return new BaseHandlerInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(baseHandlerInterceptor());
    }
}

4. resources/logback 아래에 logback-default.xml 생성

<?xml version="1.0" encoding="UTF-8"?>
<configuration>


    <property name="LOG_PATTERN"
        value="%d{yyyy-MM-dd HH:mm:ss} %p %c[%method:%line] - %msg%n" />

    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${LOG_PATTERN}</Pattern>
        </layout>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

4. 서버를 띄우고 달라진 로그 형식 확인

Logback 사용하기

1. depenedency 추가

<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
<dependency>
    <groupId>org.bgee.log4jdbc-log4j2</groupId>
    <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
    <version>1.16</version>
</dependency>

2. application.properties 수정

# DB 설정
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.jdbc-url=jdbc:log4jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

# logback 위치 지정
logging.config=classpath:logback/logback-default.xml

 

Mybatis 활용해 데이터 초스피드로 Insert 하기

1. pom.xml에 commons-lang3 라이브러리 추가 (테스트 데이터 랜덤 문자열 생성에 사용)
2. application.properties jdbcUrl에 옵션 추가 => ?allowMultiQueries=true
3. logback-default.xml에 root level DEBUG로 변경 (로그를 보기위한)
4. Board.xml에 saveList 쿼리 추가 foreach 사용하여 배열 INSERT QUERY 사용
5. BoardRepository에 saveList 관련 기능 추가 
6. BoardController, BoardService saveList1, saveList2 10000건 데이터 생성
7. saveList1, saveList2 속도 테스트

 

enum class를 Parameter, Domain 클래스 내부 변수(종류, 분류, 코드 등)에 사용하기

1. DB Board 테이블에 BOARD_TYPE VARCHAR(10) 컬럼 추가, Board.xml 쿼리 수정 

<select id="get" parameterType="int" resultType="study.spring_vue.mvc.domain.Board">
    SELECT
        BOARD_SEQ,
        BOARD_TYPE, // 추가
        TITLE,
        CONTENTS,
    REG_DATE
    FROM T_BOARD
    WHERE BOARD_SEQ = #{boardSeq}
    ORDER BY REG_DATE DESC
</select>


2. BaseCodeLabelEnum, BoardType enum class 생성 

package study.spring_vue.mvc.domain;

public interface BaseCodeLabelEnum {

    String code();

    String label();
}
package study.spring_vue.mvc.domain;

public enum BoardType implements BaseCodeLabelEnum {

    NOTICE("공지사항"),
    FAQ("자주 묻는 질문"),
    INQUIRY("1:1 문의"),
    ;

    private String code;
    private String label;

    BoardType(String label) {
        this.code = name(); // name()을 사용하면, enum이 대입된다 (ex) NOTICE)
        this.label = label; // label에는 "공지사항"이 대입된다
    }

    @Override
    public String code() {
        return code;
    }

    @Override
    public String label() {
        return label;
    }
}


3. BoardParameter BoardType boardType 변수 추가 

package study.spring_vue.mvc.parameter;

import lombok.Data;
import study.spring_vue.mvc.domain.BoardType;

@Data
public class BoardParameter {
    private int boardSeq;
    private BoardType boardType; // 추가
    private String title;
    private String contents;

}


4. Board BoardType boardType 변수 추가 

package study.spring_vue.mvc.domain;

import lombok.Data;

import java.util.Date;

@Data
public class Board {

    private int boardSeq;
    private BoardType boardType; // 추가됨
    private String title;
    private String contents;
    private Date regDate;

}


5. BaseCodeLabelEnumJsonSerializer 클래스 추가 

JSON 변환시 BaseCodeLabelEnum 클래스에 대한 변환을 동일하게 처리

package study.spring_vue.conf;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import study.spring_vue.mvc.domain.BaseCodeLabelEnum;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class BaseCodeLabelEnumJsonSerializer extends JsonSerializer<BaseCodeLabelEnum> {
    @Override
    public void serialize(BaseCodeLabelEnum baseCodeLabelEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("code", value.code());
        map.put("label", value.label());
        jsonGenerator.writeObject(map);

    }
}


6. WebConfiguration ObjectMapper, MappingJackson2JsonView Bean 등록  

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule simpleModule = new SimpleModule();
    simpleModule.addSerializer(BaseCodeLabelEnum.class, new BaseCodeLabelEnumJsonSerializer());
    objectMapper.registerModule(simpleModule);
    return objectMapper;
}

@Bean
public MappingJackson2JsonView mappingJackson2JsonView() {
    MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
    jsonView.setContentType(MediaType.APPLICATION_JSON_VALUE);
    jsonView.setObjectMapper(objectMapper());
    return jsonView;
}


7. Swagger에서 save 호출 
8. Swagger에서 list 조회 결과 확인  

Mybatis 조건 걸어 조회하기

1. pom.xml에 commons-lang3 디펜던시 추가

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>3.12.0</version>
</dependency>

2. Mybatis 문법 활용해 SQL 파일 수정

- <where>

- <if test=조건> : if 조건이 true가 되었을 때, 태그 내 SQL문을 처리

- @를 사용하면 JAVA static method 접근이 가능

- @패키지 + 클래스명@메소드명

<select id="getList" parameterType="study.spring_vue.mvc.dto.BoardSearchDTO" resultType="study.spring_vue.mvc.domain.Board">
    SELECT
        BOARD_SEQ,
        BOARD_TYPE,
        TITLE,
        CONTENTS,
        REG_DATE
    FROM T_BOARD
    <where>
        <if test="@org.apache.commons.lang3.ObjectUtils@isNotEmpty(keyword)">
            AND B.TITLE LIKE CONCAT('%', #{keyword}, '%')
        </if>
    </where>
    ORDER BY REG_DATE DESC
</select>
@GetMapping
@ApiOperation(value="detail", notes="lookup detailed board information")
public BaseResponse<List<Board>> getList(@ApiParam BoardSearchDTO parameter){
    return new BaseResponse<List<Board>>(service.getList(parameter));
}

 

배열(다중값) 검색 기능 구현을 위한 Mybatis foreach 사용

검색 조건을 추가하기 위해 BoardSearchDTO에 boardTypes 추가

package study.spring_vue.mvc.dto;

import lombok.Data;
import study.spring_vue.mvc.domain.BoardType;

@Data
public class BoardSearchDTO {
    private String keyword;
    private List<BoardType> boardTypes; // 추가

    public BoardSearchDTO() {
        
    }
}

Board.xml에 아래 내용 추가

<if test="@org.apache.commons.lang3.ObjectUtils@isNotEmpty(boardTypes)">
    AND B.BOARD_TYPE IN (
    <foreach collection="boardTypes" item="value" separator=",">
        #{value}
    </foreach>
    )
</if>

 

목록 페이징 처리 방법(HandleArgumentResolver, Mysql limit/offset 활용)

 

프런트엔드 연결하기

application.properties에서 server.port=포트번호

 

CORS 에러가 나면 웹 설정 클래스(ex) WebConf.java) 를 열어주고 addCorsMappings 메소드를 생성해줌

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**").allowedOrigins("http://localhost:8080");
}

 

반응형