20220516 복습

2022 - 0516 - 복습


package com.jslhrd.sample;

import org.springframework.stereotype.Component;

import lombok.Data;

@Component //스프링에게 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시
@Data //Lombok(setter,생성자,toString()등)을 자동 생성하는 어노테이션
public class Chef {
     
}


package com.jslhrd.sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Data;
import lombok.Setter;

@Component //스프링에게 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시
@Data //Lombok(setter,생성자,toString()등)을 자동 생성하는 어노테이션
public class Restaurant {

     @Setter(onMethod_ = @Autowired) // 의존성
     private Chef chef;
}


package com.jslhrd.sample;

import static org.junit.Assert.assertNotNull;

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.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class) //현재 테스트 코드가 스프링을 실행하는 역할을 할 것이다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") //필요한 객체들을 스프링 내에 객체로 등록(Spring's Bean)
@Log4j //Lombok을 이용하여 로그기록하는 Logger를 변수로 생성.
public class SampleTests {

     @Setter(onMethod_ = @Autowired) //@Autowired = 해당 인스턴스 변수가 스프링으로부터 자동으로 주입해 달라는 표시.
     private Restaurant restaurant;

     @Test
     public void testExist() {

          assertNotNull(restaurant); //restaurant변수가 null이 아니어야만 테스트가 성공한다는 뜻.

          log.info(restaurant);
          log.info("------------------");
          log.info(restaurant.getChef());
     }
}


package com.jslhrd.persistence;

import static org.junit.Assert.fail;
import java.sql.Connection;
import java.sql.DriverManager;

import org.junit.Test;

import lombok.extern.log4j.Log4j;

@Log4j
public class JDBCTests {

     static {
          try {
               Class.forName("oracle.jdbc.driver.OracleDriver");
          } catch (Exception e) {
               e.printStackTrace();
          }
     }

     @Test
     public void testConnection() {
          try {
               Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","system","123456");
               log.info(con);
               log.info("성공");
               Class.forName("oracle.jdbc.driver.OracleDriver");
          } catch (Exception e) {
               log.info("실패");
               e.printStackTrace(); //
               fail(e.getMessage());
          }
     }

}


import static org.junit.Assert.fail;

import java.sql.Connection;

import javax.sql.DataSource;

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.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class DataSourceTests {

     @Setter(onMethod_ = @Autowired)
     private DataSource ds;

     @Test
     public void testConnection(){

          try(Connection con = ds.getConnection()) {

               log.info(con);
               log.info("success!!!");

          } catch (Exception e) {
               e.printStackTrace();
               fail(e.getMessage());
          }
     }
}


package com.jslhrd.domain;

import java.sql.Date;

import lombok.Data;

@Data
//Lombok(setter,생성자,toString()등)을 자동 생성하는 어노테이션
public class BoardVO {

     private long bno;
     private String title;
     private String content;
     private String writer;
     private Long hit;
     private Date regdate;
     private Date updatedate;
}


package com.jslhrd.mapper;
import java.util.List;
import com.jslhrd.domain.BoardVO;

public interface BoardMapper {

     public List<BoardVO> getList();

     public void insert(BoardVO board);

     public void insertSelectKey(BoardVO board);

     public BoardVO read(Long bno);

     public int update(BoardVO board);

     public int delete(Long bno);

}


package com.jslhrd.mapper;

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.SpringJUnit4ClassRunner;

import com.jslhrd.domain.BoardVO;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardMapperTests {

     @Setter(onMethod_ = @Autowired)
     private BoardMapper mapper;

     @Test
     public void testGetList() {
          mapper.getList().forEach(board -> log.info(board));
     }

     @Test
     public void testInsert() {
          BoardVO board = new BoardVO();
           board.setTitle("insert");
          board.setContent("insert");
           board.setWriter("insert");
          mapper.insert(board);
           log.info("-------------------insert result-----------------------");
          log.info(board);
          log.info("------------------------------------------");
     }

     @Test
     public void testInsertSelectKey() {
          BoardVO board = new BoardVO();
          board.setTitle("insert K");
          board.setContent("insert K");
          board.setWriter("insert K");
          mapper.insertSelectKey(board);
          log.info("-------------------insert Select Key result-----------------------");
          log.info(board);
          log.info("------------------------------------------");
     }

     @Test
     public void testRead() {
          BoardVO board = mapper.read(16L);
          log.info("-------------------read result-----------------------");
          log.info(board);
          log.info("------------------------------------------");
     }

     @Test
     public void testUpdate() {
          BoardVO board = new BoardVO();
          board.setBno(16L);
          board.setTitle("update");
          board.setContent("update");
          board.setWriter("update");
          log.info("UPDATE RESULT !!! : " + mapper.update(board));

     }
     @Test
     public void testDelete() {
          int count = mapper.delete(31L);
          log.info("DELETE RESULT !!! : "+count);
     }


}


package com.jslhrd.service;
import java.util.List;
import com.jslhrd.domain.BoardVO;
public interface BoardService {

     public List<BoardVO> getList();

     public BoardVO get(Long bno);

     public void insert(BoardVO board);

     public boolean update(BoardVO board);

     public boolean delete(Long bno);

}


package com.jslhrd.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.jslhrd.domain.BoardVO;
import com.jslhrd.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Service // 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용함.
@Log4j
@AllArgsConstructor // 생성자를 만들고 자동으로 주입함. (생성자를 만들지 않을 경우에는 @setter()를 이용해서 처리함)
public class BoardServiceImpl implements BoardService{

     // @Setter(onMethod_ = @Autowired)
     private BoardMapper mapper;

     @Override
     public List<BoardVO> getList(){
          log.info("GET LIST ----------------------------");
          return mapper.getList();
     }

     @Override
     public BoardVO get(Long bno) {
          log.info("GET : " + bno);
          return mapper.read(bno);
     }

     @Override
     public void insert(BoardVO board) {
          log.info("INSERT : " + board);
          mapper.insertSelectKey(board);
     }

     @Override
     public boolean update(BoardVO board) {
          log.info("UPDATE : " + board);
          return mapper.update(board) == 1;
     }

     @Override
     public boolean delete(Long bno) {
          log.info("DELETE : " + bno);
          return mapper.delete(bno) == 1;
     }

}


package com.jslhrd.service;

import static org.junit.Assert.assertNotNull;
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.SpringJUnit4ClassRunner;
import com.jslhrd.domain.BoardVO;
import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardServiceTests {

     @Setter(onMethod_ = @Autowired)
     private BoardService service;

     @Test
     public void testExist() {
          log.info(service);
          assertNotNull(service);
     }

     @Test
     public void testGetList() {
          service.getList().forEach(board -> log.info(board));
     }

     @Test
     public void testGet() {
          log.info("GET ---------------------------------------");
          log.info(service.get(17L));
     }
     @Test
     public void testInsert() {
          log.info("INSERT --------------------------------------");
          BoardVO board = new BoardVO();
          board.setTitle("insert");
          board.setContent("insert");
          board.setWriter("insert");
          service.insert(board);
     }

     @Test
     public void testUpdate() {
          BoardVO board = service.get(17L);
          if(board == null) {
               return;
          }
          board.setTitle("update");
          board.setContent("update");
          board.setWriter("update");
          log.info("UPDATE RESULT : " + service.update(board));
     }

     @Test
     public void testDelete() {
          log.info("DELETE RESULT : " + service.delete(30L));
     }

}


package com.jslhrd.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
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 com.jslhrd.domain.BoardVO;
import com.jslhrd.service.BoardService;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Controller //스프링의 빈으로 인식할 수 있게 함.
@Log4j
@RequestMapping("/board/*") //'/board'로 시작하는 모든 처리를 BoardController가 하도록 지정.
@AllArgsConstructor
public class BoardController {

     private BoardService service;

     @GetMapping("/t1")
     public void t1() {

     }

     @GetMapping("/t2")
     public void t2() {

     }

     @GetMapping("/list")
     public void list(Model model) {
          log.info("list --------------------------------------------------");
          model.addAttribute("list",service.getList());
     }

     @GetMapping("/insert")
     public void insert() {

     }

     @PostMapping("/insert") //새롭게 등록된 게시물의 번호를 같이 전달(RedirectAttributes)
     public String insert(BoardVO board, RedirectAttributes rttr) {
          log.info("INSERT : " + board);
          service.insert(board);
          rttr.addFlashAttribute("result", board.getBno());
          return "redirect:/board/list";
     }

     @GetMapping({"/get","/update"}) // get방식의 get(),update()는 bno값을 받아 BoardVO를 전달하는 동일한 처리방식
     public void get(@RequestParam("bno") Long bno, Model model) { //bno를 좀 더 명시적으로 처리(@RequestParam), 화면쪽으로 게시물 전달(Model)
          log.info("get --------------------------------------------------");
          model.addAttribute("board",service.get(bno));
     }

     @PostMapping("/update")
     public String update(BoardVO board, RedirectAttributes rttr) {
          log.info("update --------------------------------------------------");
          if(service.update(board)) {
               rttr.addFlashAttribute("result", "update_success");
          }
          return "redirect:/board/list";
     }

     @PostMapping("/delete")
     public String delete(@RequestParam("bno") Long bno, RedirectAttributes rttr) {
          log.info("delete --------------------------------------------------");
          if(service.delete(bno)) {
               rttr.addFlashAttribute("result","delete_success");
          }
          return "redirect:/board/list";
     }


}


package com.jslhrd.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.SpringJUnit4ClassRunner;
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.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration //Servlet의 ServletContext 이용. 스프링에서는 WebApplicationContext라는 존재를 이용.
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j
public class BoardControllerTests {

     @Setter(onMethod_ = @Autowired)
     private WebApplicationContext ctx;
     private MockMvc mockMvc;

     @Before //@Before가 적용된 메서드는 모든 테스트 전에 매번 실행되는 메서드.
     public void setup() {
          this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
     } // MockMvc = 가짜 MVC (URL,파라미터 등을 가짜로 브라우저에서 사용하는 것처럼 하여 Controller를 실행 가능.)
     @Test
     public void testList() throws Exception {
          log.info("test");
          log.info(
               mockMvc.perform(MockMvcRequestBuilders.get("/board/list"))
                    .andReturn()
                    .getModelAndView()
                    .getModelMap()
          );
     }

     @Test
     public void testInsert() throws Exception {
          log.info("INSERT----------------------------------------------");
          String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/insert")
               .param("title","test new")
               .param("content","test new")
               .param("writer","test new")
               ).andReturn().getModelAndView().getViewName();

          log.info(resultPage);
     }

     @Test
     public void testGet() throws Exception {
          log.info("GET----------------------------------------------");
          mockMvc.perform(MockMvcRequestBuilders.get("/board/get")
               .param("bno","36")
               ).andReturn().getModelAndView().getViewName();
     }

     @Test
     public void testUpdate() throws Exception {
          log.info("UPDATE----------------------------------------------");
          String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/update")
               .param("bno","34")
               .param("title","new update")
               .param("content","new update")
               .param("writer","new update")
               ).andReturn().getModelAndView().getViewName();
          log.info(resultPage);
     }

     @Test
     public void testDelete() throws Exception {
          log.info("DELETE----------------------------------------------");
          String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/delete")
               .param("bno","33")
               ).andReturn().getModelAndView().getViewName();
          log.info(resultPage);
     }


}


>>> web.xml 인코딩 & Security 로그인

<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml /WEB-INF/spring/security-context.xml <!-- security-context.xml을 로딩하도록 빈 설정 --> </param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 한글깨짐 현상 처리 시작 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter </filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 한글깨짐 현상 처리 끝 --> <!-- Spring Security 시작 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring Security 끝 --> </web-app>


>>> footer.jsp

<script> $(document).ready(function() { $('#dataTables-example').DataTable({ responsive: true }); $(".sidebar-nav") .attr("class","sidebar-nav navbar-collapse collapse") .attr("aria-expanded",'flase') .attr("style","height:1px") }); </script>

>>> list.jsp


<script type="text/javascript">
$(document).ready(function() {

     var result = '<c:out value="${result}"/>';
     console.log(result);
     checkModal(result);
     history.replaceState({},null,null);

          function checkModal(result) {
               if (result === '' || history.state) {
                    return;
               }
               if (parseInt(result) > 0) {
                    $(".modal-body").html(
                         "게시글 " + parseInt(result) + " 번이 등록되었습니다.");
               }else {
                    $(".modal-body").html("값이 전달되지 않습니다.");
               }
               $("#myModal").modal("show");
          }
     $("#regBtn").on("click",function() {
          self.location="/board/insert";
     });

});
</script>

>>> update.jsp

<script> $(document).ready(function(){ var formObj = $("form"); $('button').on("click",function(e){ e.preventDefault(); var operation = $(this).data("oper"); console.log(operation); if(operation==='delete'){ formObj.attr("action","/board/delete"); }else if(operation==='list'){ //move to list self.location="/board/list"; return; }formObj.submit(); }); $("p").click(function(){ $(this).hide(); }); }); </script>


>>> WEB-INF/spring 폴더 내에 생성

<?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:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 5.0버전은 에러가 발생 버그 때문에 지우기 --> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/sample/all" access="permitAll" /> <security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')" /> <security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')" /> <!-- <security:form-login /> --> <security:form-login login-page="/customLogin" /> <!-- 로그인창으로 강제 이동 시 해당하는 페이지 --> <!-- <security:access-denied-handler error-page="/accessError" /> --> </security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="member" password="{noop}member" authorities="ROLE_MEMBER" /> <security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN" /> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>


>>> src/main/java -> com.jslhrd.controller 에 생성.

package com.jslhrd.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import lombok.extern.log4j.Log4j; @Log4j @RequestMapping("/sample/*") @Controller public class SampleController { @GetMapping("/all") public void doAll() { log.info("DO ALL -----------------------"); } @GetMapping("/member") public void doMember() { log.info("logined Member --------------------"); } @GetMapping("/admin") public void doAdmin() { log.info("Only Admin--------------------------"); } }


>>> src/main/java -> com.jslhrd.controller 에 생성.

package com.jslhrd.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class CommonController { @GetMapping("/customLogin") public void loginInput() { } }

< Spring 기초 >




>>> pom.xml
12라인 -> 5.0.7
64라인 -> 1.2.17
116라인 -> 4.12
139라인 -> 3.5.1
141라인 -> 1.8
142라인 -> 1.8
-----------------------------------------------------------------------------------------------------
>>> root-context.xml

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">

     <property name="driverClassName"
          value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
     <property name="jdbcUrl"
          value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"></property>
     <property name="username" value="db53"></property>
     <property name="password" value="123456"></property>

</bean>

<!-- HikariCP configuration -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
     destroy-method="close">
          <constructor-arg ref="hikariConfig" />
</bean>

<bean id="sqlSessionFactory"
     class="org.mybatis.spring.SqlSessionFactoryBean">
          <property name="dataSource" ref="dataSource">
</bean>

<mybatis-spring:scan
     base-package="com.jslhrd.mapper" />

<context:component-scan
     base-package="com.jslhrd.service">

-----------------------------------------------------------------------------------------------------
>>> buildpath
mysql-connector-java-8.0.28.jar
ojdbc8.jar
-----------------------------------------------------------------------------------------------------
>>>src/main/resources
log4jdbc.log4j2.properties 파일 생성
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator 내용입력
-----------------------------------------------------------------------------------------------------
>>>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j

@Setter(onMethod_ = @Autowired)
@Select("select sysdate from dual")

@Service // 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용함.
@Log4j
@AllArgsConstructor // 생성자를 만들고 자동으로 주입함.

<BoardController.java>
@Controller
@Log4j
@RequestMapping("/board/*")
@AllArgsConstructor

<BoardControllerTests.java>
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
               "file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j

>>>Tomcat 더블클릭 - Modules - Edit - controller 부분 지우기
-----------------------------------------------------------------------------------------------------
P.173
>>>Oracle 테이블

사용자 추가 후

system/123456

db53/123456


create user db53 identified by 123456;
grant connect,resource to db53;
grant create view to db53;

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');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user01');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user02');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user03');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user04');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user05');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user06');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user07');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user08');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user09');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user10');

-----------------------------------------------------------------------------------------------------
>>> BoardMapper.xml (@Select 어노테이션을 써도 되지만, 쿼리문이 복잡해질 경우 xml 파일로 관리하는게 유리하다 !!!)

src/main/resources -> com 폴더 -> jslhrd 폴더 -> mapper 폴더 생성 후, 그 안에 BoardMapper.xml 파일 생성
(com.jslhrd.mapper 패키지 명과 동일한 틀로)

<?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.jslhrd.mapper.BoardMapper">

     <!-- 부등호 들어가면 CDATA 처리 !!! -->

     <select id="getList" resultType="com.jslhrd.domain.BoardVO">
          <![CDATA[
               select * 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="com.jslhrd.domain.BoardVO">
          select * from tbl_board where bno = #{bno}
     </select>

     <update id="update">
          update tbl_board
          set title=#{title},
          content=#{content},
          writer=#{writer},
           updateDate=sysdate
          where bno=#{bno}
     </update>

     <delete id="delete">
          delete from tbl_board where bno=#{bno}
     </delete>

</mapper>

-----------------------------------------------------------------------------------------------------
src/main/resources -> com 폴더 -> jslhrd 폴더 -> mapper 폴더 생성 후, 그 안에 TimeMapper.xml 파일 생성
(com.jslhrd.mapper 패키지 명과 동일한 틀로)

<?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.jslhrd.mapper.TimeMapper">
     <select id="getTime2" resultType="string">
          select sysdate from dual
     </select>
</mapper>

--------------------------------------------------------------------------------------
>>> web.xml 인코딩 & Security 로그인

<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml /WEB-INF/spring/security-context.xml <!-- security-context.xml을 로딩하도록 빈 설정 --> </param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 한글깨짐 현상 처리 시작 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter </filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 한글깨짐 현상 처리 끝 --> <!-- Spring Security 시작 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring Security 끝 --> </web-app>
--------------------------------------------------------------------------------------
>>> Modal 코드

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
     <div class="modal-dialog">
          <div class="modal-content">
               <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 class="modal-title" id="myModalLabel">Modal title</h4>
               </div>
               <div class="modal-body">
(modal)
               </div>
               <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary">Save changes</button>
               </div>
          </div>
          <!-- /.modal-content -->
     </div>
     <!-- /.modal-dialog -->
</div>
<!-- /.modal -->


--------------------------------------------------------------------------------------
>>> security-context.xml
(WEB-INF / spring 폴더 내에 생성)
(Namespaces 에서 security 항목 체크 !!!)
<?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:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 5.0버전은 에러가 발생 버그 때문에 지우기 --> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/sample/all" access="permitAll" /> <security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')" /> <security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')" /> <!-- <security:form-login /> --> <security:form-login login-page="/customLogin" /> <!-- 로그인창으로 강제 이동 시 해당하는 페이지 --> <!-- <security:access-denied-handler error-page="/accessError" /> --> </security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="member" password="{noop}member" authorities="ROLE_MEMBER" /> <security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN" /> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>

https://mvnrepository.com/ <- dependency 검색
https://start.spring.io/ <- Spring Start Page

- 세팅이 반이다 !
- Test 중요 !
- build path (mysql-connector-java-8.0.28.jar , ojdbc8.jar)
- pom.xml 계속 수정

MVC

   (Model View Controller)

   Presentation - Client의 요청을 받아 Business에게 처리를 전달.
   Business - 실제 요청에 대한 처리를 담당. (Service)
   Persistence - Business의 처리에 따라 데이터베이스에 접근. 저장,조회,삭제 등 수행.

Layered Architecture


   각 계층은 자신의 계층이 갖는 책임에만 충실하도록 개발해야 한다.

View

Model Model

Presentation
@Controller

Model Model

Business
@Service

DTO Model

Persistence

DTO Model

DB
(Oracle)



초기 설정/관리해야 할 .XML

p.608
    pom.xml
    web.xml
    root-context.xml
    servlet-context.xml
    security-context.xml (로그인 처리를 위해 생성)


Interceptor

p.606
    스프링 시큐리티의 기본 동작 방식은 서블릿의 여러 필터 + 인터셉터를 이용.
    필터 = 스프링과 무관하게 서블릿 자원.
    인터셉터 = 스프링의 빈으로 관리되며 스프링의 컨텍스트 내에 속함
    ( 스프링 내부에서 컨트롤러를 호출할 때 관여하기 때문에 스프링의 컨텍스트 내의 모든 자원을 활용 가능. )
    + web.xml에 필터&bean 설정 !


Authentication(인증) & Authorization(인가)

p.615
    Authentication = '자신을 증명'
    Authorization = '권한 부여'

    AuthenticationManager = 가장 중요한 역할. 다양한 방식의 인증을 처리.
    ProviderManager = 인증에 대한 처리를 AuthenticationProvider라는 타입의 객체를 이용해서 처리.
    AuthenticationProvider = 실제 인증 작업을 진행. 이때, 인증된 정보에는 권한에 대한 정보를 같이 전달.
    UserDetailService = 인터페이스의 구현체는 실제로 사용자의 정보와 사용자가 가진 권한의 정보를 처리해서 반환하게 됨.

    -스프링 시큐리티를 커스터마이징 하는 방식-
    1. AuthenticationProvider를 직접 구현함.
    2. 실제 처리를 담당하는 UserDetailService를 구현하는 방식
    대부분은 2번으로 충분. 하지만, 새로운 프로토콜&인증구현방식을 직접 구현할 때에는 1번을 직접 구현.


username

p.620
    일반적인 경우 '사용자의 아이디 = userid' 를 의미하지만,
    스프링 시큐리티에서는 '사용자의 아이디 = username' 에 해당함에 주의.

    스프링 시큐리티의 User는 인증 정보와 권한을 가진 객체.
    ( 본 프로젝트는 MemberVO 라는 클래스 사용 )

    인증과 권한은 security-context.xml에서 UserDetailService를 이용하여 실제 처리함.


CSRF

p.634
    Cross-site request forgery
    스프링 시큐리티에서 POST방식을 이용하는 경우, 기본적으로 CSRF 토큰 사용.
    CSRF 토큰은 사용자가 임의로 변하는 난수의 토큰값을 서버에서 체크하는 방식.
    POST 전송 시, 토큰의 값이 다르면 작업을 처리하지 않는 방식.
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />



상위 폴더 패키지 클래스




src/main/java
com.jslhrd.sample Chef.java
Restaurant.java


com.jslhrd.controller
BoardController.java (C)(Pre)
HomeController.java
SampleController.java
CommonController.java
LoginController.java
com.jslhrd.mapper BoardMapper.java ( I )(Per)
TimeMapper.java
com.jslhrd.domain BoardVO.java (C)(Per)
com.jslhrd.service BoardService.java (I)(Ser)
BoardServiceImpl.java (C)(Ser)




src/test/java
com.jslhrd.sample SmapleTests.java
com.jslhrd.controller BoardControllerTests.java (C)(Pre)

com.jslhrd.persistence
DataSourceTests.java
JDBCTests.java
TimeMapperTests.java
com.jslhrd.mapper BoardMapperTests.java (C)(Per)
com.jslhrd.service BoardServiceTests.java (C)(Ser)

src/main/resources
com/jslhrd/mapper BoardMapper.xml
TimeMapper.xml
. log4jdbc.log4j2.properties





webapp/WEB-INF/views

board
list.jsp (전체 목록)
insert.jsp (게시글 등록)
get.jsp (상세 조회)
update.jsp (수정 및 삭제)
includes headr.jsp
footer.jsp

sample
all.jsp
member.jsp
admin.jsp
. home.jsp
customLogin.jsp

tbl_board
필드명 타입 설명
BNO NUMBER(10) 게시글 번호
TITLE VARCHAR(200) 제목
CONTENT VARCHAR(2000) 내용
WRITER VARCHAR(50) 작성자
HIT NUMBER(10) 조회수
REGDATE DATE 작성일
UPDATEDATE DATE 수정일