SampleRestController.java
package net.developia.spring02.controller;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.java.Log;
import net.developia.spring02.domain.SampleDTO;
@RestController
@RequestMapping("/restful")
@Log
public class SampleRestController {
@GetMapping("/ex06")
public @ResponseBody SampleDTO ex06() {
log.info("/ex06............");
SampleDTO dto = new SampleDTO();
dto.setAge(20);
dto.setName("홍길동");
return dto;
}
}
-> json이나 text를 ajax로 주고받을 때 가장 많이 사숑하는 방식이다. (@ResponseBody)
SampleController.java
@GetMapping("/ex07")
public ResponseEntity<String> ex07() {
log.info("/ex07............");
String msg = "{\"name\" : \"홍길동\"}";
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", "application/json;charset=UTF-8");
return new ResponseEntity<>(msg, header, HttpStatus.OK);
}
https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.5
pom.xml 일부
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
root-context.xml 일부
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<property name="maxUploadSize" value="104857560"></property>
<property name="maxUploadSizePerFile" value="2097152"></property>
<property name="uploadTempDir" value="file:/Users/jeong-yoon/dev/upload/tmp"></property>
<property name="maxInMemorySize" value="10485756"></property>
</bean>
SampleController.java 일부
@GetMapping("/exUpload")
public void exUpload() {
log.info("/exUpload................................");
}
exUpload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<div>
<input type='file' name='files'>
</div>
<div>
<input type='file' name='files'>
</div>
<div>
<input type='file' name='files'>
</div>
<div>
<input type='file' name='files'>
</div>
<div>
<input type='file' name='files'>
</div>
<div>
<input type='submit'>
</div>
</form>
</body>
</html>
SampleController.java 일부
@PropertySource("classpath:sample.properties")
...
@Value("${upload_path}") String uploadPath;
@PostMapping("/exUploadPost")
public void exUploadPost(ArrayList<MultipartFile> files) {
files.forEach(file -> {
log.info("----------------------");
log.info("name : " + file.getOriginalFilename());
log.info("size : " + file.getSize());
});
}
src/main/java/sample.properties
upload_path=/Users/jeong-yoon/dev/upload/tmp
http://localhost:8080/sample/exUpload 실행화면
톰캣 서버 설정
ace.sql
create sequence seq_board;
create table tbl_board (
bno number(10, 0),
title varchar2(200) not null,
content varchar2(2000) not null,
writer varchar2(50) not null,
regdate date default sysdate,
updatedate date default sysdate
);
alter table tbl_board add constraint pk_board
primary key (bno);
insert into tbl_board (bno, title, content, writer)
values (seq_board.nextval, '테스트 제목', '테스트 내용', 'user00');
commit;
select * from tbl_board;
BoardVO.java
package net.developia.spring03.domain;
import java.util.Date;
import lombok.Data;
@Data
public class BoardVO {
private Long bno;
private String title;
private String content;
private String writer;
private Date regdate;
private Date updateDate;
}
BoardMapper.java
package net.developia.spring03.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import net.developia.spring03.domain.BoardVO;
public interface BoardMapper {
@Select("select * from tbl_board where bno > 0")
public List<BoardVO> getList();
}
BoardVO.java
package net.developia.spring03.domain;
import java.util.Date;
import lombok.Data;
@Data
public class BoardVO {
private Long bno;
private String title;
private String content;
private String writer;
private Date regdate;
private Date updateDate;
}
BoardMapper.java
package net.developia.spring03.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import net.developia.spring03.domain.BoardVO;
import net.developia.spring03.domain.Criteria;
public interface BoardMapper {
//@Select("SELECT * FROM tbl_board WHERE bno > 0")
public List<BoardVO> getList();
//public List<BoardVO> getListWithPaging(Criteria cri);
public BoardVO read(Long bno);
public void insert(BoardVO board);
public void insertSelectKey(BoardVO board);
public int delete(Long bno);
public int update(BoardVO board);
/*
public int getTotalCount(Criteria cri);
*/
}
BoardMapperTests.java
package net.developia.spring03.mapper;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import lombok.extern.log4j.Log4j;
import net.developia.spring03.domain.BoardVO;
@WebAppConfiguration
@RunWith(SpringRunner.class)
@ContextConfiguration("file:**/*-context.xml")
@Log4j
public class BoardMapperTests {
@Autowired
private BoardMapper mapper;
@Test
public void testGetList() {
mapper
.getList()
.forEach(board -> {
log.info(board);
});
for(BoardVO boardVO:mapper.getList()) {
log.info(boardVO.getContent());
}
}
@Test
public void testRead() {
BoardVO board = mapper.read(5L);
log.info(board);
}
@Test
public void testInsert() {
BoardVO board = new BoardVO();
board.setTitle("그대에게");
board.setContent("숨가쁘게 살아가는 순간 속에도");
board.setWriter("신해철신해철신해철신해철신해철신");
mapper.insert(board);
log.info(board);
}
@Test
public void testInsertSelectKey() {
BoardVO board = new BoardVO();
board.setTitle("난 알아요2");
board.setContent("이 밤이 흐르고 흐르면2");
board.setWriter("서태지2");
mapper.insertSelectKey(board);
log.info(board);
}
@Test
public void testDelete() {
int count = mapper.delete(3L);
log.info("DELETE COUNT : " + count);
if (count == 0) fail("쿼리는 정상 수행되었으나 해당하는 게시물이 없음.");
}
@Test
public void testUpdate() {
BoardVO board = new BoardVO();
board.setBno(5L);
board.setTitle("수정된 제목입니다");
board.setContent("수정된 내용입니다");
board.setWriter("정현철");
int count = mapper.update(board);
log.info("UPDATE COUNT : " + count);
}
/*
@Test
public void testPaging() {
Criteria cri = new Criteria();
cri.setPageNum(1);
cri.setAmount(10);
List<BoardVO> list = mapper.getListWithPaging(cri);
list.forEach(board -> log.info(board.getBno()));
}
@Test
public void testSearch() {
Criteria cri = new Criteria();
cri.setKeyword("새로");
cri.setType("W");
List<BoardVO> list = mapper.getListWithPaging(cri);
list.forEach(board -> log.info(board));
}
*/
}
BoardMapper.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="net.developia.spring03.mapper.BoardMapper">
<select id="getList" resultType="BoardVO">
<![CDATA[
SELECT bno, title, content, writer, regdate, updatedate
FROM tbl_board
WHERE bno > 0
]]>
</select>
<insert id="insert">
insert into tbl_board (bno, title, content, writer)
values (seq_board.nextval, #{title}, #{content}, #{writer})
</insert>
<insert id="insertSelectKey">
<selectKey keyProperty="bno" order="BEFORE" resultType="long">
select seq_board.nextval from dual
</selectKey>
insert into tbl_board (bno, title, content, writer)
values (#{bno}, #{title}, #{content}, #{writer})
</insert>
<select id="read" resultType="BoardVO">
select bno, title, content, writer, regdate, updatedate
from tbl_board
where bno = #{bno}
</select>
<delete id="delete">
delete tbl_board
where bno = #{bno}
</delete>
<update id="update">
update tbl_board
set title = #{title},
content = #{content},
writer = #{writer},
updateDate = sysdate
where
bno = #{bno}
</update>
<!--
<sql id="criteria">
<trim prefix="(" suffix=") AND " prefixOverrides="OR">
<foreach item='type' collection="typeArr">
<trim prefix="OR">
<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>
</choose>
</trim>
</foreach>
</trim>
</sql>
<select id="getListWithPaging" resultType="net.developia.spring03.domain.BoardVO">
<![CDATA[
select
bno, title, content, writer, regdate, updatedate
from
(
select /*+ INDEX_DESC(tbl_board pk_board) */
rownum rn, bno, title, content, writer, regdate, updatedate
from
tbl_board
where
]]>
<include refid="criteria"></include>
<![CDATA[
rownum <= #{pageNum} * #{amount}
)
where rn > (#{pageNum}-1) * #{amount}
]]>
</select>
<select id="getTotalCount" resultType="int">
select count(*) from tbl_board where
<include refid="criteria"></include>
bno > 0
</select>
-->
</mapper>
BoardService.java
package net.developia.spring03.service;
import java.util.List;
import net.developia.spring03.domain.BoardVO;
public interface BoardService {
public void register(BoardVO board);
public BoardVO get(Long bno);
public boolean modify(BoardVO board);
public boolean remove(Long bno);
public List<BoardVO> getList();
//public List<BoardVO> getList(Criteria cri);
// 전체 데이터 개수
//public int getTotal(Criteria cri);
}
BoardServiceImple.java
package net.developia.spring03.service;
import java.util.List;
import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import net.developia.spring03.domain.BoardVO;
import net.developia.spring03.mapper.BoardMapper;
@Log
@Service
@AllArgsConstructor
public class BoardServiceImpl implements BoardService {
private BoardMapper mapper;
@Override
public void register(BoardVO board) {
log.info("register..............." + board);
mapper.insertSelectKey(board);
}
@Override
public BoardVO get(Long bno) {
log.info("get................." + bno);
return mapper.read(bno);
}
@Override
public boolean modify(BoardVO board) {
log.info("modify.........." + board);
return mapper.update(board) == 1;
}
@Override
public boolean remove(Long bno) {
log.info("remove...." + bno);
return mapper.delete(bno) == 1;
}
@Override
public List<BoardVO> getList() {
log.info("getList............................");
return mapper.getList();
}
// @Override
// public List<BoardVO> getList(Criteria cri){
// log.info("get List with Creteria : " + cri);
//
// return mapper.getListWithPaging(cri);
// }
// 전체 데이터 개수
/*@Override
public int getTotal(Criteria cri) {
log.info("get total count");
return mapper.getTotalCount(cri);
}*/
}
BoardServiceTests.java
package net.developia.spring03.service;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.log;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import lombok.extern.log4j.Log4j;
import net.developia.spring03.domain.BoardVO;
import net.developia.spring03.domain.Criteria;
@WebAppConfiguration
@RunWith(SpringRunner.class)
@ContextConfiguration("file:**/*-context.xml")
@Log4j
public class BoardServiceTests {
@Autowired
private BoardService service;
@Test
public void testExist() {
log.info(service);
assertNotNull(service);
}
@Test
public void testRegister() {
BoardVO board = new BoardVO();
board.setTitle("service 새로 작성하는 글");
board.setContent("service 새로 작성하는 내용");
board.setWriter("service newbie");
service.register(board);
log.info("생성된 게시물의 번호 : " + board.getBno());
}
@Test
public void testGetList() {
log.info(service.getList());
service.getList().forEach(board -> log.info(board));
// service.getList(new Criteria(2, 10)).forEach(board -> log.info(board));
}
@Test
public void testGet() {
log.info(service.get(17L));
}
@Test
public void testDelete() {
log.info("REMOVE RESULT : " + service.remove(9L));
}
@Test
public void testUpadte() {
BoardVO board = service.get(10L);
if( board == null ) {
fail();
return;
}
board.setTitle("10번 service 제목 수정합니다");
log.info("MODIFY RESULT : " + service.modify(board));
}
}
BoardController.java
package net.developia.spring03.controller;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
import net.developia.spring03.domain.BoardVO;
import net.developia.spring03.domain.Criteria;
import net.developia.spring03.service.BoardService;
@Controller
@Log4j
@RequestMapping("/board/*")
@AllArgsConstructor
public class BoardController {
private BoardService service;
@PostMapping("/posttest")
public ResponseEntity<String> ex07() {
String msg = "{\"name\" : \"홍길동\"}";
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", "application/json;charset=UTF-8");
return new ResponseEntity<>(msg, header, HttpStatus.OK);
}
@GetMapping("/list")
public void list(Model model) {
log.info("list 👍👍👍👍👍👍👍👍👍👍👍👍👍👍");
model.addAttribute("list", service.getList());
}
@PostMapping("/register")
public String register(BoardVO board, RedirectAttributes rttr) {
log.info("register : " + board);
service.register(board);
rttr.addFlashAttribute("result", board.getBno());
return "redirect:/board/list";
}
/*
@GetMapping({"/get", "/modify"})
public void get(@RequestParam("bno") Long bno, @ModelAttribute("cri") Criteria cri, Model model) {
log.info("/get ir modify");
model.addAttribute("board", service.get(bno));
}
*/
@PostMapping("/modify")
public String modify(BoardVO board, @ModelAttribute("cri") Criteria cri, RedirectAttributes rttr) {
log.info("modify : " + board);
if(service.modify(board)) {
rttr.addFlashAttribute("result", "success");
}
rttr.addAttribute("pageNum", cri.getPageNum());
rttr.addAttribute("amount", cri.getAmount());
rttr.addAttribute("type", cri.getType());
rttr.addAttribute("keyword", cri.getKeyword());
return "redirect:/board/list";
// return "redirect:/board/list" + cri.getListLink(); // getListLink() 메서드를 이용하면 위 코드를 이렇게 바꿀 수 있다
}
@PostMapping("/remove")
public String remove(@RequestParam("bno") Long bno, @ModelAttribute("cri") Criteria cri, RedirectAttributes rttr) {
log.info("remove......." + bno);
if(service.remove(bno)) {
rttr.addFlashAttribute("result", "success");
}
rttr.addAttribute("pageNum", cri.getPageNum());
rttr.addAttribute("amount", cri.getAmount());
rttr.addAttribute("type", cri.getType());
rttr.addAttribute("keyword", cri.getKeyword());
return "redirect:/board/list";
// return "redirect:/board/list" + cri.getListLink(); // getListLink() 메서드를 이용하면 위 코드를 이렇게 바꿀 수 있다
}
@GetMapping("/register")
public void register() {
}
/*
public void list(Criteria cri, Model model) {
log.info("list: " + cri);
model.addAttribute("list", service.getList(cri));
// model.addAttribute("pageMaker", new PageDTO(cri, 123));
int total = service.getTotal(cri);
log.info("total : " + total);
model.addAttribute("pageMaker", new PageDTO(cri, total));
}
*/
}
BoardControllerTests.java
package net.developia.spring03.controller;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import lombok.extern.log4j.Log4j;
@WebAppConfiguration
@RunWith(SpringRunner.class)
@ContextConfiguration("file:**/*-context.xml")
@Log4j
public class BoardControllerTests {
@Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
}
@Test
public void testList() throws Exception {
log.info(
mockMvc.perform(MockMvcRequestBuilders.get("/board/list"))
.andReturn()
.getModelAndView()
.getModelMap());
}
@Test
public void testListPaging() throws Exception {
log.info(mockMvc.perform(
MockMvcRequestBuilders.get("/board/list")
.param("pageNum", "1")
.param("amount", "10"))
.andReturn().getModelAndView().getModelMap());
}
@Test
public void testRegister() throws Exception {
String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/register")
.param("title", "테스트 새글 제목")
.param("content", "테스트 새글 내용")
.param("writer", "user00")
).andReturn().getModelAndView().getViewName();
log.info(resultPage);
}
@Test
public void testGet() throws Exception {
log.info(mockMvc.perform(MockMvcRequestBuilders
.get("/board/get")
.param("bno", "12"))
.andReturn()
.getModelAndView()
.getModelMap());
}
@Test
public void testModify() throws Exception{
String resultPage = mockMvc
.perform(MockMvcRequestBuilders.post("/board/modify")
.param("bno", "13")
.param("title", "수정된 테스트 새글 제목")
.param("content", "수정된 테스트 새글 내용")
.param("writer", "user00")).andReturn().getModelAndView().getViewName();
log.info(resultPage);
}
@Test
public void testRemove() throws Exception {
// 삭제전 데이터베이스에 게시물 번호를 확인할 것
String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/remove")
.param("bno", "12")
).andReturn().getModelAndView().getViewName();
log.info(resultPage);
}
}
log4jdbc.log4j2.properties
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
</layout>
</appender>
<!-- Application Loggers -->
<logger name="net.developia.spring03">
<level value="info" />
</logger>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core">
<level value="info" />
</logger>
<logger name="org.springframework.beans">
<level value="info" />
</logger>
<logger name="org.springframework.context">
<level value="info" />
</logger>
<logger name="org.springframework.web">
<level value="info" />
</logger>
<logger name="jdbc.audit">
<level value="warn" />
</logger>
<logger name="jdbc.resultset">
<level value="warn" />
</logger>
<logger name="jdbc.connection">
<level value="warn" />
</logger>
<!-- Root Logger -->
<root>
<priority value="info" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="net.developia.spring03" />
</beans:beans>
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig"
p:driverClassName="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"
p:jdbcUrl="jdbc:log4jdbc:oracle:thin:@localhost:1521/xepdb1"
p:username="ace"
p:password="ace" />
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"
c:configuration-ref="hikariConfig" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource"
p:typeAliasesPackage="net.developia.spring03.domain"/>
<mybatis-spring:scan
base-package="net.developia.spring03.mapper" />
</beans>