Skip to content

rimgosu/SpringStudy

Repository files navigation

image

SpringStudy

Settings

필수세팅

  1. 전자정부프레임워크

  2. 스프링, 자바 업데이트 -pom.xml

    • 스프링 4.0.0 => 5.0.2로 최신화
    • 자바 1.6 => 1.8로 최신화
    • 프로젝트 클릭 => Alt+F5 => Force update if snapshots
  3. 아파치 톰캣 등록 :

    image

    • 프로젝트 끌어서 Server 탭의 Tomcat에 드래그해서 끌어 당겨야함
  4. 오류메시지 지우기 :

  5. 한글 깨짐 해결 :


DB 세팅

image image image

라이브러리/설정 Maven Repository 링크 설명
MyBatis MyBatis 3.4.6 SQL 매핑 프레임워크
HikariCP HikariCP 3.4.1 고성능 JDBC 연결 풀
MySQL Connector Java MySQL 5.1.42 MySQL 데이터베이스 드라이버
Spring JDBC Spring JDBC 5.0.2.RELEASE 스프링의 JDBC 통합 지원
MyBatis Spring MyBatis-Spring 1.3.2 MyBatis와 Spring 통합
루트 컨텍스트 설정.txt 루트컨텍스트설정.txt root-context.xml에 붙여넣을 설정

세부 세팅 (라이브러리)

  1. 부트스트랩 : 디자인 탬플릿 적용

  2. Lombok

/* lombok => 생성자 만들어주는 api
 @Data => getter/setter
 @AllArgsConstructor => 전체 생성자
 @NoArgsConstructor => 빈 생성자
 @ToString => toString */

mysql 세팅

  1. C++ 다운로드
  2. kr.spring.mapper
    • Type : MySql_5.1 ver

Lecture Note

9월 5일 (스프링 개요& 게시판 만들기-1)

  1. ContextPath 변경하는 법
    • server.xml, context 태그, path 변경
<Context docBase="SpringMVC03" path="/controller" reloadable="true" source="org.eclipse.jst.jee.server:SpringMVC03"/></Host>
  1. @Controller
    • @RequestMapping(value = "/", method = RequestMethod.GET)
    • => HomeController.java에서 root 주소에서의 작업을 처리함

9월 6일

  1. web.xml => 스프링 정보 총괄, 톰캣이 읽을 때 가장 먼저 읽는 파일

    • Root Spring => root-context.xml (여기에 jdbc 설정 해줘야함 - 루트컨텍스트 설정.txt)
    • ContextLoaderListener
    • DispatcherServlet => servlet-context.xml (디스패쳐 서블릿이 생성될 때 이 파일 참조함)
  2. servlet-context.xml

    • <context:component-scan base-package="kr.spring.controller" />
    • 여기 기본 context 매핑되어있음.
  3. root-context.xml

    • 루트컨텍스트 설정.txt => root-context.xml 붙여 넣기
    • hikariConfig : db url, id, pw 정보 담고 있음
    • dataSource : getConnection() [hikariConfig를 참조]
    • SqlSessionFactoryBean : psmt, getClose() [dataSource를 참조]
    • mybatis-spring:scan : kr.spring.mapper 패키지에 있는 인터페이스 찾을거임.
  4. BoardMapper.java (인터페이스)

@Mapper // MyBatis 인터페이스를 찾기위해 달아주는 부분
public interface BoardMapper {
	
	@Select("SELECT * FROM BOARD")
	public List<Board> getLists();

}

9월 7일

  1. 리다이렉트 방식

    • return "redirect:주소";
    • return "redirect:boardList.do";
  2. 간편한 파라미터 받기 :

      1. 기본생성자
      1. getter/setter
      1. dto의 속성 이름 (name="DTO의 속성 이름")
    • 이 셋 조건을 충족하면 request.getParameter 할 필요 없이 dto자체로 받을 수 있다.
  3. MyBatis XML Mapper

      1. Mapper 이름 동일
      1. <select id="Mapper 매서드 이름과 동일">
<select id="getLists" resultType="kr.spring.entity.Board">
	SELECT * FROM BOARD ORDER BY INDATE DESC
</select>

<insert id="boardInsert">
	INSERT INTO BOARD (TITLE,	CONTENT,	WRITER)
	VALUES(#{title}, #{content}, #{writer})
</insert>
  1. @RequestParam("idx") int idx :

    • request.getParameter과 동일한 역할.
  2. 줄바꿈 :

    • <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
    • <body> <% pageContext.setAttribute("newLineChar", "\n"); %> </body>
    • ${fn:replace( vo.content, newLineChar, "<br>") }
    • ${fn:split( vo.indate, " ")[0] }

9월 11일 (PathVariable, 비동기 통신)

  1. @RequestParam("idx") int idx => int idx

    • 로 짧게 써도 파라미터 가져올 수 있다.
    • ※단, 파라미터의 name과 같은 변수명을 써야
  2. <input type="hidden" name="idx" value="${vo.idx }">

    • type="hidden" 옵션으로 데이터 더 보낼 수 있음.
  3. PathVariable

    image

    • get 방식에서, key값을 설정을 안하고 값을 넘겨줄 수 있다.
      1. boardContent.do?idx=${dto.idx } => boardContent.do/${dto.idx }
      1. /boardContent.do => /boardContent.do/{idx}
      1. @RequestParam("idx") => @RequestParam("idx")
      1. ../ : 경로 안으로 들어온 처리가 되어서, 경로 밖으로 나가줘야함.
  4. jakson

    • json 응답 라이브러리
<!-- json 방식으로 응답하기 위한 API -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.9.8</version>
</dependency>
  1. @ResponseBody
    • 비동기임을 알려주는 어노테이션
public @ResponseBody List<Board> boardList() {}
  1. Ajax
<script type="text/javascript">
// 처음 실행될 때 자동 실행 => 생성자 느낌
// html 다 로딩되고 아래 코드 실행
$(document).ready(function() {
	loadList();
});

function loadList() {
	// 게시글 리스트 가져오기
	// ajax - 요청 url, 어떻게 데이터 받을지, 요청방식 등 .. => 객체{}로 넣기
	$.ajax({
		url : "boardList.do",
		type : "get",
		dataType : "json",
		success : makeView, // callback 함수
		error : function() {alert("error");}
	});
}

function makeView(data) {
	console.log(data);
}
</script>

9월 12일 (비동기 통신-2)

  1. jquery 반복문 활용
$.each(data, function(index, obj) {
				listHtml += "<tr>";
				listHtml += "<td>" + index + "</td>";
				listHtml += "<td>" + obj.title + "</td>";
				listHtml += "<td>" + obj.writer + "</td>";
				listHtml += "<td>" + obj.indate + "</td>";
				listHtml += "<td>" + obj.count + "</td>";
				listHtml += "</tr>";
			});
			
			$("#view").html(listHtml);
  1. &nbsp;

    • 줄바꿈
  2. javascript $().serialize() fData = $("#frm").serialize();

      1. {"키" : 값, "키" : 값}
      1. serialData = "title=" + title + "&content=" + content;

9월 13일 (REST-1)

  1. Rest 전송 방식

    URL에 통일성, 요청하는 URL+전송방식 묶어서 요청 가능!

    • URL의 통일성, 단순화
  2. @RestController

@RestController
public class BoardRestController {
	@Autowired
	private BoardMapper mapper;
}
  1. BoardRestController => 비동기 방식

    • @ResponseBody 필요 없다.
      => 어차피 비동기 방식이기 때문!
  2. 매핑

    • @RequestMapping("/주소")
@RequestMapping("/board")
@RestController
public class BoardRestController {
	@RequestMapping("/all")
	public List<Board> boardList() {...}
}
  1. 매핑 주소 사용 방법
    • $.ajax({url : "board/주소"})
$.ajax({url : "board/all"})
  1. Mapping Type:
    1. @RequestMapping : get, post
    2. @GetMapping : get
    3. @PostMapping : post
    4. @DeleteMapping : delete
    5. @PutMapping : update

9월 14일 (REST-2)

  1. update / put 매서드
$.ajax({
	url : "board/update",
	type : "put",
	contentType : "application/json;charset=utf-8",
	data : JSON.stringify({
		"idx" : idx,
		"title" : title,
		"content" : content,
		"writer" : writer
	}),
	...
})
@PutMapping
@RequestMapping("/update")
public void boardUpdate(@RequestBody Board board) {
	System.out.println("게시글 수정 수행");
	mapper.boardUpdate(board);
}

@RequestBody :
자바 객체로 변환해주는 것임.
data를 JSON.stirngify()로 json => stirng으로 변환하므로 자바 객체로 변환해줄 필요가 있다.

  1. 네비게이션 바 BOOTSTRAP

  2. contextPath 전역변수로 지정

<c:set var="contextPath" value="${pageContext.request.contextPath}"></c:set>

9월 15일

  1. modal :
    • modal bootstrap
    • 사용자의 이목을 집중시키기 위한 그래픽 인터페이스 창
$("#checkMessage").text("사용할 수 있는 아이디입니다.");
$("#myModal").modal("show");

9월 18일

  1. RedirectAttributes
    • 리다이렉트 방식으로 이동할 때 보낼 데이터를 저장하는 객체
    • 리다이렉트할 때 보내고 사라짐
    • (↔ forward model)
// 매개변수 받기
public String join(RedirectAttributes rttr);

// 사용하기
rttr.addFlashAttribute("msgType", "실패메세지");
rttr.addFlashAttribute("msg", "모든 내용을 채워주세요.");
// 모델 사용 복습 (포워드 방식)
public String boardlist(Model model)

model.addAttribute("list", list);
  1. $(document).ready()
    • 모든 문서가 로드 되었을 때 쓰는 자바스크립트 함수
<script>
$(document).ready(function() {})
</script>
  1. required
    • input란이 공백이면 제출할 수 없음
<input required>
  1. HttpSession
    • 스프링의 세션사용
public String join(HttpSession session)

session.setAttribute("member", member);

프로젝트 임포트

  1. 프로젝트 임포트하는법
    1. 이름이 같은 프로젝트 Delete, 실제 경로로 들어가서 그 프로젝트 있는지 확인
    2. 같은 경로로 .zip 파일 붙여넣기
    3. import-import-next-archaive-.zip파일 선택
    4. build path-JRE System Library - Workspace default JRE
    5. Server Runtime 연동 안되어있으면, Add Library-Server Runtime-Finish
    6. 서버 등록

9월 19일

  1. webapp/resources
    • 이미지 등 저장공간
    • servlet-context.xml에 매핑되어있음.
<resources mapping="/resources/**" location="/resources/" />
  1. bootstrap tabs

https://www.w3schools.com/bootstrap/tryit.asp?filename=trybs_tabs_dynamic&stacked=h

image

  1. c:if - 라디오 버튼
<c:if test="${member.memGender eq '남자'}"></c:if>
<c:if test="${member.memGender eq '여자'}"></c:if>
  1. insert, update : cnt
    • update, insert 성공적으로 수행했으면 cnt=1
int cnt = mapper.update(member);
  1. 부트스트랩 아이콘

    https://www.w3schools.com/bootstrap/bootstrap_ref_comp_glyphs.asp

<span class="glyphicon glyphicon-log-in">로그인</span>
<span class="glyphicon glyphicon-log-out">로그아웃</span>

9월 20일 (프로필 사진 등록)

파일업로드

image

  1. 파일업로드 jsp
<form action="${contextPath }/imageUpdate.do" method="post" enctype="multipart/form-data">
	<input type="file" name="memProfile">
</form>
  1. 파일업로드 maven

https://mvnrepository.com/artifact/servlets.com/cos

<!-- https://mvnrepository.com/artifact/servlets.com/cos -->
<dependency>
    <groupId>servlets.com</groupId>
    <artifactId>cos</artifactId>
    <version>05Nov2002</version>
</dependency>
  1. 파일업로드 controller
    • 파일업로드 객체는 파라미터로 받아올 수 없다.
    • 받아올 수 있는 5가지

      데이터, 저장경로, 최대 크기, 인코딩, 파일명 중복제거

public String imageUpdate(HttpServletRequest request) {
	MultipartRequest multi = null;
	String savePath = request.getRealPath("resources/upload");
	int fileMaxSize = 10 * 1024 * 1024;
	try {
			multi = new MultipartRequest(request, savePath, fileMaxSize, "utf-8", new DefaultFileRenamePolicy());
		} catch (IOException e) {
			e.printStackTrace();
		}
	...
}
  1. resource/upload 폴더 생성

  2. 보내면 다음 경로에 파일이 업로드 되어있는 것을 볼 수 있다 (서버 측 폴더)

C:\eGovFrame-4.0.0\workspace.edu.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\SpringMVC03\resources\upload

  1. 이전 프로 파일 삭제
String oldImg = mapper.getMember(memId).getMemProfile();
File oldFile = new File(savePath + "/" + oldImg);
if(oldFile.exists()) {
			oldFile.delete();
		}
  1. 파일 무결성 검사
// 내가 방금 업로드한 파일 정보
File file = multi.getFile("memProfile");

if (file != null) {
	// 확장자 가져오기
	String ext = file.getName().substring(file.getName().lastIndexOf(".") + 1);
	// PNG, png
	ext = ext.toUpperCase();
	
	if (!(ext.equals("PNG") || ext.equals("GIF") || ext.equals("JPG") || ext.equals("JPEG"))) {
		if(file.exists()) {
			file.delete();
			rttr.addFlashAttribute("msgType", "실패메세지");
			rttr.addFlashAttribute("msg", "이미지 파일만 가능합니다.(png, jpg, gif)");
			
			return "redirect:/imageForm.do";
		}
	}
	
}

9월 21일

SpringMVC03 끝 SpringMVC04

  1. 조건문 안에서 el 식을 쓰고 싶다면 문자열로 감싸주어야 한다
<script>
	if("${mvo.memId}" == obj.memId) {...}
	console.log("member.memId : "+"${member.memId}");
</script>

.xml → .java

  1. web.xml 안쓰겠습니다 선언

pom.xml

<build>
	<plugins>
		<!-- web.xml 안쓰겠습니다 선언. -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.2.0</version>
				<configuration>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>

			...
  1. .xml 삭제

image

  1. Config.java 생성

WebConfig.java
ServletConfig.java
RootConfig.java

  • AbstractAnnotationConfigDispatcherServletInitializer (추상 클래스) 상속
  • add unimplement method (추상 클래스를 상속받았으므로 필수 함술르 만들어줘야함)

image

설정 유형 XML 설정 파일 Java 설정 파일 설명
웹 설정 web.xml WebConfig.java 웹 컨텍스트 관련 설정. 서블릿 매핑과 컨텍스트 파라미터를 포함합니다.
루트 설정 root-context.xml RootConfig.java 애플리케이션 컨텍스트 설정. 데이터 소스, 서비스, 레포지토리 등을 포함합니다.
서블릿 설정 servlet-context.xml ServletConfig.java 서블릿 컨텍스트 관련 설정. 뷰 리졸버와 컨트롤러를 포함합니다. @ComponentScan을 사용하여 여러 컨트롤러를 지정할 수 있습니다.

persistence-mysql.properties

src/main/resources/persistence-mysql.properties

  • db 연결을 위한 설정파일

image

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/com
jdbc.user=com
jdbc.password=com01

RootConfig.java (연결)

@PropertySource({"classpath:persistence-mysql.properties"})
public class RootConfig {
	@Autowired
	Environment env;

	...
}

9월 22일 (Security)

SpringMVC04
SpringMVO05

Spring Security Settings

  1. security 버전 추가 & org.springframework.security 추가.

pom.xml

<!-- Spring Security를 하기위한 버전 추가-->
<org.springsecurity-version>5.0.2.RELEASE</org.springsecurity-version>
<!-- Spring Security API 추가 -->
<dependency>
	<!-- web에서 Srpnig Security를 사용하기 위한 api -->
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-web</artifactId>
	<version>${org.springsecurity-version}</version>
</dependency>
<dependency>
	<!-- Spring Security를 사용하기 위한 API -->
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-config</artifactId>
	<version>${org.springsecurity-version}</version>
</dependency>
<dependency>
	<!-- Spring Security를 편리하게 사용하기위한 태그라이브러리 사용 API -->
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-taglibs</artifactId>
	<version>${org.springsecurity-version}</version>
</dependency>
  • 위 두 문장을 추가하면 스프링 버전이 업데이트 되므로 alt+f5 - Force update 체크해서 업데이트 해줘야함.

image

  1. AbstractSecurityWebApplicationInitializer

kr.spring.config/SecurityInitializer.java

  • 자동으로 보안 관련 객체들이 생성되어 스프링 컨테이너(메모리 공간)으로 올라간다
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer{}
  1. WebSecurityConfigurerAdapter

kr.spring.config/SecurityConfig

  1. CSRF

Cross-Site Request Forgery. 사이트 간 요청 위조의 줄임말.

  • CSRF 설정을 하지 않으면 로그인, 회원가입 등 403 에러가 뜬다.
  • 해결 방안 : 토큰을 줘서 확인함

joinForm.jsp
loginForm.jsp
updateForm.jsp

<!-- 보안 토큰 설정 -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">

imageForm.jsp

<!-- 보안 토큰 설정 (get 방식으로 내보내기) -->
<form action="${contextPath }/imageUpdate.do?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">

main.jsp (javascript 비동기 통신)

<script>
	var csrfHeaderName = "${_csrf.headerName}";
	var csrfTokenValue = "${_csrf.token}";
	$.ajax({
		...
		beforeSend : function(xhr){
			xhr.setRequestHeader(csrfHeaderName, csrfTokenValue);
		},
		...
	});
</script>	

웹페이지

<!-- 다음과 같이 자동으로 csrf 토큰 값이 들어오는 걸 볼 수 있다. -->
<input type="hidden" name="_csrf" value="04872be9-ce98-4b5b-a42c-2070b798c971">

4-1. CSRF UTF-8 인코딩

SecurityConfig.java

  • 보안쪽 클래스를 지나면서 인코딩이 깨진다. 따라서 인코딩을 Security쪽에 따로 해줘야
@Override
protected void configure(HttpSecurity http) throws Exception {
	// 요청에 대한 보안 설정하는 곳
	CharacterEncodingFilter filter = new CharacterEncodingFilter();
	filter.setEncoding("utf-8");
	filter.setForceEncoding(true);
}

비밀번호 암호화

  1. Auth 테이블 생성
create table auth(
	no 			int		not null	auto_increment,
	memid		varchar(50)		not null,
	auth		varchar(50)		not null,
	primary key(no),	
	constraint fk_member_auth foreign key(memid) references member(memid)
);
  1. Auth 엔티티 생성

  2. Member엔티티에서 Auth 엔티티 가져오기

  3. form 태그에 권한 엔티티 추가 및 무결성검사

  4. bean으로 패스워드 인코더 등록

SecurityConfig

@Bean // password 인코딩 기능을 메모리에 올리기
public PasswordEncoder passwordEncoder() {
	return new BCryptPasswordEncoder();
}
//사용
@Autowired
private PasswordEncoder pwEncoder;
// 비밀번호 암호화하기
String encyPw = pwEncoder.encode(member.getMemPassword());
System.out.println(encyPw);

확인해보면 '$2a$10$eE3kIhtbnLAELjZECaucgenZSMJFHbO1AZuIuOL3enjg4keEqyJke'와 같이 암호화 된 것을 볼 수 있다.

  1. DB 테이블이 변경되었으므로 ID="JOIN" SQL문 수정
<insert id="join" parameterType="kr.spring.entity.Member">
  INSERT INTO MEMBER(MEMIDX, MEMID, MEMPASSWORD, MEMNAME, MEMAGE, MEMGENDER,
MEMEMAIL, MEMPROFILE)
VALUES(
(SELECT IFNULL(MAX(MEMIDX) + 1, 1) FROM MEMBER MEM),
#{memID}, #{memPassword}, #{memName}, #{memAge},
#{memGender}, #{memEmail}, #{memProfile}
)
</insert>

9월 25일

a. <resultMap>
1. result를 추가해주기 위한 도구
2. 배열 받아오기 위해선 <collection />

<resultMap type="kr.spring.entity.Auth" id="authMap">
	<id property="no" column="no"/>
	<result property="memId" column="memId"/>
	<result property="auth" column="auth"/>
</resultMap>

<resultMap type="kr.spring.entity.Member" id="memberMap">
	<id property="memIdx" column="memIdx"/>
	<result property="memId" column="memId"/>
	<result property="memPassword" column="memPassword"/>
	<result property="memName" column="memName"/>
	<result property="memAge" column="memAge"/>
	<result property="memGender" column="memGender"/>
	<result property="memEmail" column="memEmail"/>
	<result property="memProfile" column="memProfile"/>
	<collection property="authList" resultMap="authMap"/>
</resultMap>
<select id="getMember" parameterType="String" resultMap="memberMap">
	SELECT * 
	  FROM MEMBER mem LEFT OUTER JOIN AUTH auth
		ON mem.MEMID = auth.MEMID
	 WHERE mem.MEMID = #{memId}
</select>

b. 비밀번호 일치여부 체크

  1. pwEncoder.matches()
  2. true, false 반환
boolean pwCheck = pwEncoder.matches(member.getMemPassword(), m.getMemPassword());

9월 26일

SpringMVC06

3단계 보안 (스프링 시큐리티 제공 로그인, 회원가입)

image

  • 계정 정보 보관 장소 : Session → Spring Context Holder

a. 권한 설정

SecurityConfig.java

  • 로그인
  • 로그아웃
  • 특정페이지 권한 설정
http
	.authorizeRequests() /* 요청에 따른 권한을 처리하겠다 */
		.antMatchers("/") /* 어떠한 경로로 왔을 때 권한처리를 할 것인지 */
			.permitAll() /* 누구나 접근 가능하게끔 전체 권한 */
				.and() 
			.formLogin() /* 로그인 보안기능 추가 */
				.loginPage("/loginForm.do") 
				.loginProcessingUrl("/login.do")
				.permitAll() 
				.and() 
			.logout() /* 로그아웃기능 */
				.invalidateHttpSession(true) 
				.logoutSuccessUrl("/")
				.and()
			.exceptionHandling().accessDeniedPage("/access-denied"); /* 로그인도 안하고 특정페이지에 접근하려고할 때 막기 */
					

MemberController.java
access-denied.jsp

@GetMapping("/access-denied")
	public String showAccessDenied() {
		return "access-denied";
	}

b. Spring Security와 mapper 연결

kr.spring.security/MemberUserDetailsService.java

  • UserDetailsService 인터페이스 상속
  • 메서드를 가져와야 한다.
  • mapper의 로그인 기능을 연결.

c. 스프링 보안 엔티티

kr.spring.entity/MemberUser.java

  • org.springframework.security.core.userdetails.User 상속
  • Member 엔티티 객체로 가져옴

d. 로그인 매퍼

MemberMapper.xml

<select id="login" resultMap="memberMap">
	SELECT * FROM MEMBER mem LEFT OUTER JOIN Auth auth on
	mem.MEMID = auth.MEMID WHERE mem.MEMID = #{username}
</select>

e. MemberUserDetailsService 사용

kr.spring.config/SecurityConfig.java

@Bean // 우리가 만든 MemberUserDetailsService 메모리로 올려 사용하겠다.
public UserDetailsService MemberUserDetailsService() {
	return new MemberUserDetailsService(); 
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	auth.userDetailsService(MemberUserDetailsService()).passwordEncoder(passwordEncoder());
}

f. 기존 login() 함수 삭제

MemberController.java

g. name을 Spring Security의 Default 값으로 변경

loginForm.jsp

  • name="memID"name="username"
  • name="memPassword"name="password"

Security 활용

a. 세션 → ?error

  • 기존에는 세션에 로그인 정보가 있엇지만 지금은 Security로 인해 세션에 없다. (Security Context에 있음.)
  • 모달창을 수정해줘야함.
// url 뒤에 ?error 확인
if(${param.error != null}) {
	$("#messageType").attr("class", "modal-content panel-warning");
	$(".modal-body").text("아이디와 비밀번호를 확인하세요");
	$(".modal-title").text("실패메시지");
	$("#myMessage").modal("show");
}

b. 세션에 로그인 정보 없으면 어떻게 활용하나.

  • Security 태그 라이브러리 선언
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

c. Spring Security에서 제공하는 계정정보 (SecurityContext 안에 계정정보 가져오기)

  • mvo에 계정 정보 담기
<c:set var="mvo" value="${SPRING_SECURITY_CONTEXT.authentication.principal}"/>
  • auth에 권한 정보 담기
<c:set var="auth" value="${SPRING_SECURITY_CONTEXT.authentication.authorities}"/>

d. security:authorize 태그 사용

  • 인증 안했으면 태그 안을 실행
<security:authorize access="isAnonymous()">
	...
</security:authorize>
  • 인증 했으면 태그 안을 실행
<security:authorize access="isAuthenticated()">
	...
</security:authorize>

e. mvo를 사용하기 위해선..

  • mvo.memProfilemvo.member.memProfile
  • mvo의 member의 memProfile, 이런식으로 한단계 더 거쳐야 가져올 수 있다.

f. 권한을 태그를 활용해 가져오기

<security:authorize access="hasRole('ROLE_USER')">
	U
</security:authorize>
<security:authorize access="hasRole('ROLE_MANAGER')">
	M
</security:authorize>
<security:authorize access="hasRole('ROLE_ADMIN')">
	A
</security:authorize>

9월 27일 (Security 로그아웃, 회원정보수정, 프로필사진)

a. 로그아웃

  • 더 이상 세션에 로그인 정보가 저장되어 있지 않다.
  • session.invalidate();로 로그아웃되는 것처럼 보이지만 그렇지 않다.
  • 세션으로 로그인 하는 것은 키로 jsession 아이디 쿠키를 받는다. 마찬가지로
  • Security에서 키로 세션을 받고, 이를 해제해서 로그아웃이 된 것 처럼 보이는 것이다.
    • 해결 방법 : http.logout()

a-1. <button onclick="logout()"> == <a href="javascript:logout()">

a-2. 비동기 통신으로 SecurityConfig.java에 있는 http.logout() 기능으로 요청

header.jsp

  • post 방식으로 보내주어야 한다.
function logout() {
	$.ajax({
		url : "${contextPath}/logout",
		type : "post",
		beforeSend : function(xhr) {
			xhr.setRequestHeader(csrfHeaderName, csrfTokenValue);
		},
		success : function() {
			location.href = "${contextPath}/";	
		},5
		error : function() {
			alert("error");
		}
		
	});
}

b. 회원 정보 수정

MemberController.java

  • Authentication 객체 : 회원의 정보가 담겨있다.
  • 자동완성 조심 : security.core.Authentication
  • authentication.getPrincipal(); : return 타입은 User이다. 다운 캐스팅 필요
  • 세션에 담는 일은 전부 다음 코드로 대체된다고 생각하면 됨.

Session 대신 Authentication

import org.springframework.security.core.Authentication;

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

MemberUser userAccount = (MemberUser) authentication.getPrincipal();
Authentication newAuthentication =
	createNewAuthentication(authentication, userAccount.getMember().getMemID());
						SecurityContextHolder.getContext().setAuthentication(newAuthentication);
  • createNewAuthentication()이란 함수를 생성하고,
  • 회원 정보를 새로 받아 재로그인해준다.
private Authentication createNewAuthentication(Authentication currentAuth, String username) {
	UserDetails newPrincipal = memberUserDetailsService.loadUserByUsername(username);
	UsernamePasswordAuthenticationToken newAuth =
			new UsernamePasswordAuthenticationToken(
					newPrincipal, currentAuth.getCredentials(), newPrincipal.getAuthorities());
	
	newAuth.setDetails(currentAuth.getDetails());
	
	return newAuth;
}

c. 프로필 사진 변경

imageForm.jsp

  • 기존 방식은 id를 RequestGetParameter로 가져왔지만,
  • 지금은 Security의 보안 때문에 id 정보를 받아올 수 없다.
  • input:hidden으로 아이디를 multi 객체에 보내고 거기서 다시 가져오는 것과 같다.
  • Session 대신 Authentication을 사용하면 된다.

10월 4일 (3 tier)

SpringMVC07

image
  • MVC 패턴에 서비스 층이 추가됨
  • 서비스 층은 실질적인 업무를 담당한다.
  • kr.spring.service 패키지 생성.

Service Setting

  • kr.spring.service
    • BoardService.java (인터페이스)
    • BaordServiceImpl.java (클래스) 기능구현
  • servlet-context.xml
    • service 패키지를 매핑해줘야 한다.
    • <context:component-scan base-package="kr.spring.service" />

댓글 기능

  • 글과 댓글을 테이블 하나에 전부 표시할 수 있다.
삭제여부 댓글단계 댓글순서 보드그룹 보드번호 제목
0 0 0 2 1 삭제된 게시글입니다.
1 1 1 2 2 ㄴ 아 오늘 아침 쌀쌀하던데?
1 1 2 2 3 ㄴ 맞아맞아 오늘 날씨 쌀쌀함
1 2 3 2 4  ㄴ 이분 쌀쌀하다해놓고 반팔입고옵
1 0 0 1 5 어제 저으로 골뱅이 탕 먹었는데 괜찮음 ㅎㅎ
1 1 1 1 6 ㄴ 거짓말치지마세요!!
1 2 2 1 7  ㄴ 무슨 사인데 이렇게 잘 암?

junit 테스트

image

junit Setting
  • 버전 다운그레이드

       <dependency>
     	<groupId>junit</groupId>
     	<artifactId>junit</artifactId>
     	<version>4.12</version>
     	<scope>test</scope>
       </dependency>    
    
  • log4j 업그레이드

       <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.17</version>
    
  • dependency 추가

     <dependency>
     	<groupId>org.springframework</groupId>
     	<artifactId>spring-test</artifactId>
     	<version>${org.springframework-version}</version>
     </dependency>
    
  • src.test.java.kr.spring.mapper.DataSourceTest.java

    • Autowired로 객체를 가져오고 @Test 어노테이션을 달고 junit 테스트를 진행하면 된다.

10월 5일

fmt

  • 날짜 포맷을 지정할 수 있는 태그 라이브러리
  • import
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
  • 사용
<fmt:formatDate value="${vo.indate}" pattern="yyyy-MM-dd"/>

동적 sql

  • SELECT INULL의 문법이 보기 어려우므로 selectKey 문법으로 별칭을 달아줄 수 있다.
<insert id="insertSelectKey" parameterType="kr.spring.entity.Board">
<selectKey keyProperty="idx,boardGroup" resultType="kr.spring.entity.Board" order="BEFORE">
	SELECT IFNULL(MAX(IDX) + 1, 1) as idx,
		   IFNULL(MAX(BOARDGROUP) + 1, 1) as boardGroup
	  FROM TBLBOARD
</selectKey>
...

</insert>

10월 6일

SpringMVC07 답글기능 추가

10월 11일

  1. <c:out value="${vo.title}"></c:out> : XSS 방어를 위해 사

JSTL 정리

TagsDescription
c:out<% = ... %> 태그 작동 방식과 유사한 표현식의 결과를 표시
c:import상대 또는 절대 URL을 검색하여 내용을 'var'의 문자열, 'varReader'의 Reader 또는 페이지에 표시
c:set평가중인 표현식의 결과를 'scope'변수에 설정
c:remove특정 범위에서 지정된 범위 변수를 제거하는 데 사용
c:catch본문에서 발생하는 Throwable 예외를 포착하는 데 사용
c:if조건을 테스트하는 데 사용되는 조건부 태그이며 표현식이 참인 경우에만 본문 내용을 표시
c:choose, c:when, c:otherwise평가 된 조건이 true 인 경우 본문 내용을 포함하는 간단한 조건부 태그
c:forEach기본 반복 태그, 고정 된 횟수 또는 초과 수집 동안 중첩 된 본문 내용을 반복
c:forTokens제공된 델리 미터로 분리 된 토큰을 반복
c:param포함하는 'import'태그의 URL에 매개 변수를 추가
c:redirect브라우저를 새 URL로 리디렉션하고 컨텍스트 기준 URL을 지원
curl
  1. a태그 → submit태그
  • get.jsp
  • 버튼에 data-btn 속성 달아주기
<button data-btn="reply">
<button data-btn="modify">
<button data-btn="list">
  • 자바스크립트로 버튼을 클릭했을 때 액션 추가
<script type="text/javascript">
	// 링크처리
	$(document).ready(function(){
		$("button").on("click", function(e){
			var formData = $("#frm");
			var btn = $(this).data("btn");
		});
	});
</script>

페이징

SpringMVC07 → SpringMVC08_Paging

  1. 페이징 기본 설정 Class

10월 12일 - 페이징2

SpringMVC08_Paging

  • pageStart ~ perPageNum
LIMIT #{pageStart}, #{perPageNum}
// 다음과 같이 쓰면 modelAttribute 바로 갱신 가능.
@ModelAttribute("cri") Criteria cri

@어노테이션 정리

분류Annotation설명
Spring Core
@Component개발자가 생성한 Class를 Spring의 Bean으로 등록하기 위한 Annotation.
@ComponentScanBean을 등록 될 클래스들을 스캔하여 Bean으로 등록해줍니다.
@Bean제어가 불가능한 외부 라이브러리 등을 Bean으로 만들 때 사용.
@AutowiredSpring에서 Bean 객체를 주입받기 위한 Annotation.
Spring MVC
@Controller해당 Class가 Controller의 역할임을 명시하기 위한 Annotation.
@RequestHeaderRequest의 header값을 가져올 수 있는 Annotation.
@RequestMappingURI의 요청과 Annotation value 값이 일치하면 실행.
@RequestParamURL의 파라미터를 메소드 인자와 매칭.
@RequestBodyBody의 데이터를 메소드 인자와 매칭.
@ModelAttributeHTTP parameter, Body 내용을 객체에 바인딩.
@ResponseBody메소드에서 리턴된 값이 View에 출력되지 않고 HTTP Response Body에 작성.
@GetMappingRequestMapping(Method=RequestMethod.GET)과 동일 역할.
@PostMappingRequestMapping(Method=RequestMethod.POST)과 동일 역할.
Spring Boot Test
@SpringBootTestSpring Boot Test에 필요한 의존성 제공.
@TestJUnit에서 테스트 대상을 표시.
Lombok
@SetterClass의 모든 필드에 대한 Setter method 생성.
@GetterClass의 모든 필드에 대한 Getter method 생성.
@AllArgsConstructor모든 필드 값을 파라미터로 받는 생성자 추가.
@NoArgsConstructor기본 생성자 자동 추가.
@ToStringClass의 모든 필드에 대한 toString method 생성.

10월 13일 - 페이징3, 검색

SpringMVC08_Paging
SpringMVC09_Search

  1. 페이징 유지
  • 매개변수로 값 받기
public String 함수(Criteria cri, RedirectAttributes rttr){}
  • 페이징 값 유지
rttr.addAttribute("page", cri.getPage());
rttr.addAttribute("perPageNum", cri.getPerPageNum());

SpringMVC08_Paging 복사, SpringMVC09_Search 붙여기

  1. sql의 JSTL (동적 sql)
  • 'search'로 묶기 : sql
<sql id="search" >
	<if test="type=='writer'">
		where writer like concat('%', #{keyword}, '%')
	</if>
	<if test="type=='title'">
		where title like concat('%', #{keyword}, '%')
	</if>
	<if test="type=='content'">
		where content like concat('%', #{keyword}, '%')
	</if>
</sql>
  • 묶은거 사용 : include
SELECT * FROM TBLBOARD
<include refid="search" />
ORDER BY BOARDGROUP DESC, BOARDSEQUENCE ASC

Spring Boot

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

Spring Boot Settings

10월 16일

  • 스프링 부트 프로젝트 만들기
  1. Tomcat 실행 중지
  2. Project Explorer - 우클릭 - New - Other - Spring Starter Project
  3. https://start.spring.io 접속 : 웹에서 편리하게 프로젝트 만들 수 있다.

image

  1. SpringMVC10_SpringInit 생성

    Key Value
    Type Maven
    Packaging Jar
    Java Version 8
    Package kr.spring
    Spring Boot Version 3.1.4
  2. 원하는 API 체크해서 넣어주기

    Category Details
    Developer Tools Lombok, Spring Boot DevTools
    Web Spring Web
    SQL 추후 학습 예정
  3. Spring Boot는 내장 Tomcat이 존재해서, Tomcat에 등록할 필요가 없다.

  4. Build Path - Java version : Workspace default JRE (자바 버전을 Workspace에 맞추겠다)

  5. resources

    Folder Details
    Static css, js
    Templates HTML
    application.properties 웹 애플리케이션의 환경 설정 파일. .yaml로 변환 가능하여 사용하기도 한다.
  6. application.properties - 우클릭- Resource - Other - UTF-8 (한글깨짐 방지)

  7. application.properties - 우클릭 - Open With - Generic Editor (Properties에서 자동완성 가능하게 함)

    server.port=8081
    server.servlet.context-path=/boot
    
  8. pom.xml 버전 수정 - 프로젝트 클릭 - alt + F5 - Force Update of Snapshots/Releases

    • Spring boot version : 2.7.3
    • java version : 1.8
    • pom.xml - 우클릭 - Spring - Add Starter
      • MySQL Driver, Spring Data JPA - pom.xml 체크
      • MySQL 추가할 때 버그 있다. groupID : mysql, artifactId : mysql-connector-java 로 고쳐줄 것
  9. SpringMvc10BootInitApplication - 우클릭 - run as - 2 Spring boot App - 주소 직접 입력해서 접속하면 됨

  10. Port 8081 was already in use. Error : 서버 중지 - 다시 실행

  11. application.properties, MySQL 설정

    # MySQL 추가 
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/com
    spring.datasource.username=com
    spring.datasource.password=com01
    
  12. application.properties, JPA*Hiberbate 설정

    # JPA 설정
    spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
    # 스키마 생성 (create, update)
    spring.jpa.hibernate.ddl-auto=create
    # JPA가 실행하고 실행된 SQL문장 보기
    spring.jpa.show-sql=true
    # 실제 JPA 구현체인 Hibernate가 동작하면서 발생하는 SQL을 포멧팅해서 출력
    spring.jpa.properties.hibernate.format_sql=true
    
  13. Board Entity 생성

    • SQL 없이 테이블 생성하기

JPA @어노테이션 정리

카테고리 어노테이션 설명
기본 어노테이션 @Entity 클래스가 엔티티임을 지정
@Table 엔티티가 매핑될 테이블 정보 지정
@Id 기본 키 필드를 지정
@GeneratedValue 기본 키 생성 전략을 지정
열 매핑 어노테이션 @Column 필드를 데이터베이스 컬럼에 매핑
@Transient 해당 필드가 데이터베이스 컬럼에 매핑되지 않게 지정
@Enumerated enum 타입을 컬럼에 매핑
@Temporal 날짜/시간 타입을 매핑
@Lob 큰 객체나 문자열 매핑 (BLOB, CLOB)
관계 매핑 어노테이션 @OneToOne 일대일 관계 매핑
@OneToMany 일대다 관계 매핑
@ManyToOne 다대일 관계 매핑
@ManyToMany 다대다 관계 매핑
@JoinColumn 외래 키 컬럼 지정
@JoinTable 다대다 관계의 연결 테이블 지정
상속 매핑 어노테이션 @Inheritance 상속 전략 지정
@DiscriminatorColumn 상속 테이블 간 구분 컬럼 지정
@DiscriminatorValue 구분 컬럼의 값 지정
기타 어노테이션 @Embedded 내장 타입 사용 지정
@Embeddable 값 타입을 내장 타입으로 정의
@AttributeOverride 내장 타입의 속성 재정의
@SecondaryTable 엔티티를 두 개 이상의 테이블에 매핑
라이프사이클 콜백 어노테이션 @PrePersist 엔티티 라이프사이클 이벤트에 대한 콜백 정의

JPA 매서드 정리

작업 메소드 설명
Select find() 단일 엔터티 검색
findAll() 모든 엔터티 검색
findById() 주어진 ID를 가진 엔터티 검색
Insert save() 새 엔터티 저장 또는 업데이트
Delete deleteById() 주어진 ID를 가진 엔터티 삭제
Update save() 이미 존재하는 엔터티의 정보 업데이트 (또는 삽입)
  1. 테이블 생성을 마쳤으면, spring.jpa.hibernate.ddl-auto=update로 지정
    • 이제 더이상 테이블을 지우고 생성하지 않음.

10월 17일 - 스프링 부트2

JPA 참고 문서

  1. kr.spring.repository
  • JpaRepository를 상속 받아야 한다.
    • <table 이름/primary key>
@Repository // @Mapper 랑 같음 (생략 가능)
public interface BoardRepository extends JpaRepository<Board, Long>{}
  • BoardRepository == MyBatis Mapper과 동일한 기능. 사용하려면 @Autowired로 사용하면된다.
// 다른 클래스
@Autowired
private BoardRepository boardRepository;
  1. kr.spring.service
Type Name Annotation
Interface BoardService
Class BoardServiceImpl @Service
  1. JPA 내장 함수 사용 (SQL문 없이 DB 기능 사용)
List<Board> list = boardRepository.findAll();
public Board get(Long idx);
boardRepository.save(vo);

Spring Boot ViewResolver 설정

  1. application.properties
spring.mvc.view.prefix=/WEB-INF/board/
spring.mvc.view.suffix=.jsp
  1. pom.xml
  • jstl 설치
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>jstl</artifactId>
</dependency>
  • jsp 설치
<dependency>
	<groupId>org.apache.tomcat.embed</groupId>
	<artifactId>tomcat-embed-jasper</artifactId>
</dependency>

부트스트랩 4

  • row - col-log-{num}
  • 원하는 크기만큼 화면 분할 가능
<div class="row">
	<div class="col-lg-2"></div>
	<div class="col-lg-5"></div>
	<div class="col-lg-5"></div>
</div>

Spring Boot Security

10월 18일 - Spring Boot Security Settings

  1. pom.xml - 우클릭 - spring - security - spring security - pom.xml 추가 - 완료
  2. spring-security-taglibs 추가
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-taglibs</artifactId>
</dependency>
  1. Member Entity
  • Spring Security에서는 반드시 username, password, role를 지정해줘야한다.
  • MemberRepository 생성
@Id
private String username;

private String password;

@Enumerated(EnumType.STRING)
private Role role;
  • /WEB-IBF/board만 ViewResolver면 안되므로, application.properties에서
  • spring.mvc.view.prefix=/WEB-INF/board/를 다음과 같이 수정해준다.
spring.mvc.view.prefix=/WEB-INF/
  1. Role Entity - Enum
  • enumeration, 상수 저장 집함
public enum Role {
	ADMIN, MANAGER, MEMBER;
}
  1. CustomUser Entity
  • Spring Context Holder에 Member Entity 정보를 담기 위해선 Spring Security에서 제공하는 User 엔티티의 형식으로 바꿔줄 필요가 있음.
  • Member → CustomUser → User → Spring Context Holder
  • Spring context Holder: 보안 금고
  1. kr.spring.config
  2. UserDetailsServiceImpl
  • UserDetailsService 기능 실행
  1. SecurityConfiguration
  • Security 환경설정

10월 23일 - Spring Boot Security 활용

  1. login.jsp - 부트스트랩 로그인페이지
  2. /resources/ 매핑
spring.mvc.static-path-pattern=/resources/**
  1. 단위테스트를 통해 Member 정보 삽입

Spring Security 정보 가져오기 - 첫번째 방법

  1. CustomUser - getter, setter 매서드 추가 @Data

  2. security 태그 추가

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
  1. CustomUser 객체에 접근해 member 정보 가져오기
    • security 태그로 가져온다.
<sec:authentication property="principal.member.name"/>
<sec:authentication property="principal.member.role"/> 
  1. <sec:authorize>
<sec:authorize access="hasRole('ADMIN')">
	내용을 작성하세요
</sec:authorize>

Spring Security 정보 가져오기 - 두번째 방법

  1. c:set
<!-- 로그인한 계정정보 -->
<c:set var="user" value="${SPRING_SECURITY_CONTEXT.authentication.principal}" />
<!-- 권한정보 -->
<c:set var="auth" value="${SPRING_SECURITY_CONTEXT.authentication.authorities}" />

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published