json viewer
https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=ko
static : 정적 리소스(html, css, js, image..)
정적 리소스 : 컴파일 대상이 아닌 것
동적 리소스 : jsp
[Get | Post 방식]
게시판 수정 1번 url : /update?bid=1
게시판 삭제 20번 url : /delete?bid=20
[restful 처리]
게시판 삭제 20번 수정 또는 삭제 url : /boards/20
>> method 방식에 따라 [/boards/20] 수정되거나 삭제됨
>> html에서는 method 방식을 get, post만 지원함
[계산 application.properties] #server port number server.port = 8282 #datasource (oracle) #spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver #spring.datasource.url=jdbc:oracle:thin:@localhost:1521/xe spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xe spring.datasource.username=scott spring.datasource.password=tiger #MyBatis #xml location mybatis.mapper-locations=classpath:mappers/`**/*.xml mybatis.type-aliases-package=edu.global.ex #jsp spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp --------------------------------------------------------------------- [계산 RestBoardController.java] package edu.global.ex.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import edu.global.ex.BoardService; import edu.global.ex.vo.BoardVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j // 로그를 사용하기 위한 어노테이션 : log.info("view_list().."); @RequestMapping("/rboard/*") // jboard로 들어오는 모든 것들은 BoardController를 생성해라 @RequiredArgsConstructor @RestController // 기존의 컨트롤러 문법과는 완전히 달라짐 | restful 처리를 위한 어노테이션 public class RestBoardController { @Autowired // (주입)객체에 주소를 줌 private BoardService boardService; // BoardService boardService = new BoardServiceImpl(); @GetMapping("/") public String rboard() { // String이면 html text로 보냄 return "<h1>이제는 restful이다</h1>"; } @GetMapping("/list") // List객체 json으로 리턴 public List<BoardVO> list() { log.info("list().."); return boardService.getList(); } // json으로 리턴된 데이터는 ajax로 받아온다. // ajax({ type:"GET", url : "http://localhost:8282/rboard/list", // success : function(result){} @DeleteMapping("/{bid}") // /rboard/1054 public int rest_delete(BoardVO boardVO) { log.info("rest_delete().."); return boardService.remove(boardVO); } /* * @DeleteMapping("/{bid}") public ResponseEntity<String> rest_delete(BoardVO * boardVO, Model model) { * * ResponseEntity<String> entity = null; log.info("rest_delete.."); * * try { int rn = boardService.remove(boardVO); // 삭제가 성공하면 성공 상태메시지 저장 * log.info("delete 넘어온 숫자:::::" + rn); * * entity = new ResponseEntity<>(String.valueOf(rn), HttpStatus.OK); } catch * (Exception e) { e.printStackTrace(); // 댓글 삭제가 실패하면 실패 상태메시지 저장 entity = new * ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST); } // 삭제 처리 * HTTP 상태 메시지 리턴 return entity; } */ @GetMapping("/{bid}") public BoardVO rest_content_view(BoardVO boardVO) { log.info("rest_content_view().."); return boardService.get(boardVO.getBid()); } // @RequestBody : json을 자바 객체로 변환하는 어노테이션 @PutMapping("/{bid}") public int rest_update(@RequestBody BoardVO boardVO) { log.info("rest_update().."); return boardService.modify(boardVO); } } --------------------------------------------------------------------- [계산 rest_lsit.html] <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() { $.ajax({ type : "GET", url : "/rboard/list/", success : function(result) { console.log(result); var htmls = ""; $("#list-table").html(""); // table을 갖고옴, html을 초기화 $("<tr>" , { html : "<td>" + "번호" + "</td>"+ // 컬럼명들 "<td>" + "이름" + "</td>"+ "<td>" + "제목" + "</td>"+ "<td>" + "날짜" + "</td>"+ "<td>" + "히트" + "</td>" }).appendTo("#list-table") // 이것을 테이블에 붙임 if(result.length < 1){ htmls.push("등록된 댓글이 없습니다."); } else { $(result).each(function(){ > htmls += '<tr>'; htmls += '<td>'+ this.bid + '</td>'; htmls += '<td>'+ this.bname + '</td>'; htmls += '<td>' for(var i=0; i < this.bindent; i++) { //for 문은 시작하는 숫자와 종료되는 숫자를 적고 증가되는 값을 적어요. i++ 은 1씩 증가 i+2 는 2씩 증가^^ htmls += '-' } htmls += '<a href="/rest_content_view.html?bid=' + this.bid + '">' + this.btitle + '</a></td>'; htmls += '<td>'+ this.bdate + '</td>'; htmls += '<td>'+ this.bhit + '</td>'; htmls += '<td>'+ '<input id=' + this.bid + " type='button' class='btn_delete' value='삭제'>" + '</td>'; htmls += '</tr>'; }); //each end htmls+='<tr>'; htmls+='<td colspan="5"> <a href="/write_view">글작성</a> </td>'; htmls+='</tr>'; } $("#list-table").append(htmls); }, error : function(e) { console.log(e); } }); }); </script> <!-- <input id="142" type="button" class="btn_delete" value="삭제"> --> <script type="text/javascript"> $(document).ready(function(){ $(document).on("click","#list-table .btn_delete", function(){ console.log($(this).attr("id")); var id = $(this).attr("id"); $(this).parent().parent().remove(); // tr태그를 지워라 $.ajax({ type : "DELETE", url : "/rboard/" + id, success: function (result) { console.log("삭제된 수" + result); }, error: function (e) { console.log(e); } }); }); }); </script> </head> <body> <table id="list-table" width="500" cellpadding="0" cellspacing="0" border="1" style="text-align: center"> </table> </body> </html> --------------------------------------------------------------------- [계산 rest_content_view.html] <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <!-- http://localhost:8282/rest_content_view.html?bid=254 --> <script type="text/javascript"> $(document).ready(function() { let searchParams = new URLSearchParams(window.location.search) console.log(searchParams.has('bid')); let bid = searchParams.get('bid') console.log(bid); $.ajax({ type : "GET", url : "/rboard/" + bid, success : function(board) { console.log(board); $("#input_hidden").val(board.bid); $("#td_bid").text(board.bid); $("#td_hit").text(board.bhit); $("#input_bname").val(board.bname); $("#input_btitle").val(board.btitle); $("#textarea_bcontent").text(board.bcontent); }, error : function(e) { console.log(e); } }) }); </script> <script type="text/javascript"> $(document).ready(function() { $("#updateForm").submit(function(event) { //prevendDefault()는 href로 연결해 주지 않고 단순히 click에 대한 처리를 하도록 해준다. event.preventDefault(); console.log("ajax 호출전"); var bname = $("#input_bname").val(); var btitle = $("#input_btitle").val(); var bcontent = $("#textarea_bcontent").text(); var bid = $("#input_hidden").val(); var form = { bid : bid, bname : bname, btitle : btitle, bcontent : bcontent }; $.ajax({ type : "PUT", url : "/rboard/" + bid, cashe : false, contentType : 'application/json; charset=utf-8', // var form객체를 json으로 보내겠다 data : JSON.stringify(form), // json으로 변경 success : function(result) { console.log(result); $(location).attr('href', '/rest_list.html') // location.href = '/rest_list.html' }, error : function(e) { console.log(e); } }) }); }); </script> </head> <body> <table id="list-table" width="500" cellpadding="0" cellspacing="0" border="1"> <form id="updateForm" action="modify" method="post"> <input id="input_hidden" type="hidden" name="bid" value=""> <tr> <td>번호</td> <td id="td_bid"></td> </tr> <tr> <td>히트</td> <td id="td_hit"></td> </tr> <tr> <td>이름</td> <td><input id="input_bname" type="text" name="bname" value=""></td> </tr> <tr> <td>제목</td> <td><input id="input_btitle" type="text" name="btitle" value=""></td> </tr> <tr> <td>내용</td> <td><textarea id="textarea_bcontent" rows="10" name="bcontent"></textarea></td> </tr> <tr> <td colspan="2"><input id="input_modify" type="submit" value="수정"> <a href="rest_list.html">목록보기</a> <a id="a-delete" href="${pageContext.request.contextPath}/rest/delete?bid=${content_view.bid}">삭제</a> <a href="reply_view?bId=${content_view.bid}">답변</a></td> </tr> </form> </table> </body> </html>
[결과값]
스프링 시큐리티(인증과 권한) = 인증과 권한을 위한 솔루션(프레임워크)
1) 인증과 권한
2) 암호화 모듈 제공
3) CSRF 방어 모듈 제공
[스텝 1]
dependency만 추가해도 Spring Security에서 제공하는 가장 기본적인 인증이 바로 적용됨
기본 로그인 화면이 가장 먼저 나올 것이다.
Username : user (기본 계정)
Password : 비밀번호는 어플리케이션 기동할때 로그로 나오는 Using generated security password 정보
Using generated security password: 0d07e7fd-0fba-403d-9eff-149ac84f4d56
This generated password is for development use only. Your security configuration must be updated before running your application in production.
------------------------------------------------------------------------------------------------
[스텝 2]
이미지(가영이)가 보이지 않는다.
우선 정적파일들은 시큐리티에 적용되지 않도록 아래와 같이 설정을 한다.
이제 더이상 리소스파일들은 스프링 시큐리티에서 관리를 하지 않는다.
@Override
public void configure(WebSecurity web) throws Exception {
// web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
}
------------------------------------------------------------------------------------------------
[스텝 3]
이제 설정에서 유저를 생성한후 , 다시 한번 접속해 보자 , 로그인 창에서 아래의 이름과 비밀번호로 접속해 보자. 그럼 헬로우 월드가 보인다.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("member").password("{noop}member").roles("USER").and()
.withUser("admin").password("{noop}admin").roles("ADMIN");
}
------------------------------------------------------------------------------------------------
[스텝 4]
home.jsp를 제대로 만들고, 아래와 같이 설정하여 / 로 접속후 home.jsp 가 나오는것을 확인한다.
@Override
protected void configure(HttpSecurity http) throws Exception {
//우선 CSRF설정을 해제한다.
//초기 개발시만 해주는게 좋다.
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/member/**").hasAnyRole("ROLE_MEMBER")
.antMatchers("/admin/**").hasAnyRole("ROLE_ADMIN")
.antMatchers("/**").permitAll();
}
------------------------------------------------------------------------------------------------
[스텝 5]
1.home.jsp를 제대로 만들고, 아래와 같이 설정하여 / 로 접속후 home.jsp 가 나오는것을 확인한다.
2 admin 페이지와 user 페이지를 만든후, 컨트롤러를 작성하여, admin 과 user 계정으로 접속후 각각의 지정된 페이지로 접속 되는지 확인한다.
protected void configure(HttpSecurity http) throws Exception {
//우선 CSRF설정을 해제한다.
//초기 개발시만 해주는게 좋다.
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/user/**").hasAnyRole("USER")
.antMatchers("/admin/**").hasAnyRole("ADMIN")
.antMatchers("/**").permitAll();
http.formLogin(); //스프링 시큐리티에 있는 기본 로그인 폼을 사용하겠다.
git hub에 올리고 싶지 않은 파일 정리
https://www.toptal.com/developers/gitignore
C:\Users\USER\Documents\workspace-sts-3.9.11.RELEASE\spring_boot_kdb_security
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
# Created by https://www.gitignore.io/api/java,macos,windows,eclipse
# Edit at https://www.gitignore.io/?templates=java,macos,windows,eclipse
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### Eclipse Patch ###
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Annotation Processing
.apt_generated
.sts4-cache/
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/java,macos,windows,eclipse
.metadata/
Servers/
*.class
*.classpath
/target/
/bin/
/.settings/
/.apt_generated_tests/
[계산 pom.xml] <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.8</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>edu.global</groupId> <artifactId>ex</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring_boot_kdb_security</name> <description>Board project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <repositories> <repository> <id>oracle</id> <url>http://www.datanucleus.org/downloads/maven2/</url> </repository> </repositories> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- spring-boot-devtools는 클래스 수정시 웹서버를 재시작하여 결과를 바로 반영 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 오라클 JDBC 드라이버 --> <dependency> <groupId>oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> <!-- MyBatis 라이브러리 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!-- MyBatis sql pretty --> <dependency> <groupId>org.bgee.log4jdbc-log4j2</groupId> <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId> <version>1.16</version> </dependency> <!-- JSP를 사용하기 위한 라이브러리 --> <!-- 톰캣 파서 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <!-- jstl 라이브러리 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> </dependencies> <build><!-- 컴파일~배포까지 --> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <url>http://146.56.137.240:8282/manager/text</url> <username>admin</username> <password>1234</password> </configuration> </plugin> <!-- cmd에 입력 ( 배포 ) : mvnw.cmd tomcat7:redeploy --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project> --------------------------------------------------------------------- [계산 application.properties] #server port number server.port = 8282 #datasource (oracle) spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.url=jdbc:oracle:thin:@localhost:1521/xe #spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy #spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xe spring.datasource.username=scott spring.datasource.password=tiger spring.devtools.livereload.enabled=true #jsp spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp --------------------------------------------------------------------- [계산 HomeController.java] package edu.global.ex.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HomeController { @GetMapping("/") public String home() { return "home"; } } --------------------------------------------------------------------- [계산 home.jsp] <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> home </body> </html> --------------------------------------------------------------------- [계산 SecurityConfig.java] package edu.global.ex.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration // @Component + 의미(설정할 수 있는 파일)//(객체 생성해서 IOC컨테이너에 넣어라) @EnableWebSecurity // 스프링 시큐리티 필터가 스프링 필터체인에 등록됨 = 스프링 시큐리티를 작동시키는 파일이라는 것을 알려줌 - 스프링한테. public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 우선 CSRF설정을 해제한다. // 초기 개발시만 해주는게 좋다. http.csrf().disable(); http.authorizeRequests() // .antMatchers("/user/**").hasAnyRole("USER") // .antMatchers("/admin/**").hasAnyRole("ADMIN") // .antMatchers("/**").permitAll(); .antMatchers("/**").hasAnyRole("ADMIN"); // id: admin, pw:admin http.formLogin(); // 스프링 시큐리티에 있는 기본 로그인 폼을 사용하겠다. } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("user").password("{noop}user").roles("USER").and().withUser("admin") .password("{noop}admin").roles("ADMIN"); } }
[결과값]