출처: https://bumcrush.tistory.com/182 [맑음때때로 여름]

구글 OAuth

https://console.cloud.google.com/

 

Google Cloud Platform

하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.

accounts.google.com

 

1. 새 프로젝트 생성

2. 사용자 동의화면 필요한 정보 입력

3. OAuth 클라리언트 ID 만들기

3-1 웹에서 사용할 거니까 웹 애플리케이션으로 해줌

리다이렉션 URI는 라이브러리를 사용하면 따로 컨트롤러에서 mapping을 해주지 않아도

/login/oauth2/code/google로 고정이댜~ 라이브러리가 알아서 처리를 해준다!

완료하면 클라이언트 ID와 비밀번호가 뜨는데 노출되지 않도록 하자~

 

 

OAuth2.0 라이브러리 사용을 위해 의존성 추가추가!

 

https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-oauth2-clien0

<!--OAUTH-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

application.yml 파일도 수정

 

/oauth2/authorization/google 주소 역시 /login/oauth2/code/google와 같이 이 주소를 써야한다.

하지만 이거만 쓰면 냅다 404가 떠버린다

 

security config 파일에 Oauth로그인페이지 설정을 해주어야한다. 구럼 잘뜸!

.and()
.oauth2Login()
.loginPage("/loginForm"); // oauth로그인페이지

 

로그인은 잘 되지만 권한이 없는 manager 페이지 같은 경우에는 403이뜬다.

이 경우에는 구글 로그인이 완료된 뒤의 후처리가 필요하다.

[ webSecurityConfigurerAdapter를 상속한 sercurityConfig ]

@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) 추가

// secured 어노테이션 활성화 & preAuthorize/PostAuthorize 어노테이션 활성화

package com.cos.security1.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity // 활성화 - 스프링 시큐리티 필터가 스프링 필터체인에 등록이 된다
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) // secured 어노테이션 활성화 & preAuthorize/PostAuthorize 어노테이션 활성화
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable(); // /login으로 갈때 스프링 시큐리티가 낚아채지 않도록

        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll()// 다른주소는 OK
                .and()
                .formLogin()
                .loginPage("/loginForm") // 로그인안햇을때 403페이지가 뜨는게 아니라 login페이지를 뜨게만들어줌
                .loginProcessingUrl("/login") //login 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행
                .defaultSuccessUrl("/"); // 로그인이 완료되면 이동할 주소


    }

    @Bean // 해당 메서드의 리턴되는 오브젝트를 ioc로 등록
    public BCryptPasswordEncoder encodePwd(){
        // 비밀번호 암호화를 위해
        return new BCryptPasswordEncoder();
    }
}

[ Contoller ]

postAuthorize는 잘 사용하지 않는다.

실행시점?의 차이. 

@Secured("ROLE_ADMIN")
@GetMapping("/info")
public @ResponseBody String info(){
    return "개인정보";
}

@PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
// @PostAuthorize()
@GetMapping("/data")
public @ResponseBody String data(){
    return "데이터정보";
}

로그인폼과 회원가입폼 HTML

더보기

로그인폼과 회원가입폼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>로그인 페이지</title>
</head>
<body>
    <h1>로그인 페이지</h1>
<hr>
 <form action="/login" method="POST">
     <input type="text" name="username" placeholder="UserName"/><br/>
     <input type="password" name="password" placeholder="Password"/><br/>
     <button>로그인</button>
 </form>

<a href = "/joinForm">회원가입을 아직 않으셨나요?</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>회원가입 페이지</title>
</head>
<body>
<h1>회원가입 페이지</h1>
<form action="/join" method="POST">
    <input type="text" name="username" placeholder="UserName"/><br/>
    <input type="password" name="password" placeholder="Password"/><br/>
    <input type="email" name="email" placeholder="Email"/><br/>
    <button>회원가입</button>
</form>

</body>
</html>

 

[ 회원가입 Contoller ]

  @PostMapping("/join")
    public String join(User user){

        System.out.println(user);


        // 2. 패스워드 암호화를 추가해줌 securityConfig에도 BcryptpasswordEncoder를 @Bean으로 등록
        String rawPassword = user.getPassword();
        String encPassword = bCryptPasswordEncoder.encode(rawPassword);
        user.setPassword(encPassword);

        
        // 1. userRepository.save(user); // 회원가입 잘됨. 비밀번호 : 1234 => 시큐리티로 로그인을 할수 없음,
        // :: 패스워드가 암호화가 안되었기 때문
        user.setRole("ROLE_USER");
        userRepository.save(user);


        return "redirect:/loginForm";
    }

[ USER MODEL ]

package com.cos.security1.model;

import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.sql.Timestamp;

@Entity
@Data
public class User {

    @Id // primary Key
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private  int id;
    private String username;
    private String password;
    private String email;
    private String role; // ROLE_USEr, ROLE_ADMIN
    @CreationTimestamp
    private Timestamp createdate;

}

 

[ USER REPORSITORY - JPA ]

package com.cos.security1.repository;

import com.cos.security1.model.User;
import org.springframework.data.jpa.repository.JpaRepository;


// CRUD 함수를 JPArepository가 들고 있음
// @Repository라는 어노테이션이 없어도 Ioc가 됨 (자동 빈등록)
// -> JpaRepository를 상속했기 때문
public interface UserRepository extends JpaRepository<User, Integer> {


    // findBy규칙 -> username 문법
    // seelct * from user where username = #{username}
    public User findByUsername(String username);
}

 

[ config 수정 ]

밑 두줄 추가.

 


public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable(); // /login으로 갈때 스프링 시큐리티가 낚아채지 않도록

        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll()// 다른주소는 OK
                .and()
                .formLogin()
                .loginPage("/loginForm") // 로그인안햇을때 403페이지가 뜨는게 아니라 login페이지를 뜨게만들어줌
                .loginProcessingUrl("/login") //login 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행
                .defaultSuccessUrl("/"); // 로그인이 완료되면 이동할 주소


    }

 

 

[ userDetails를 상속하는 클래스 생성 ]

유저정보를 저장.

package com.cos.security1.config.auth;

// 시큐리티가 /login 주소 요청이 오면 낚아채서 로그인을 진행시킴
// 로그인 진행이 완료되면 seisson을 만들어줌 (Security ContextHolder)
// 세션에 들어갈 수 있는 정보(오브젝트) > authentication 타입의 객체
// authentication 안에 User정보가 있어야 함.
// user 오브젝트 타입 > UserDetails 타입 객체

// Security Session => Authentication => UserDetails(PrincipalDetails)

import com.cos.security1.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

public class PrincipalDetails implements UserDetails {

    private User user; // 콤포지션

    public PrincipalDetails(User user){
        this.user = user;
    }


    // 해당 user의 권한을 리턴하는 곳
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collect = new ArrayList<>();
        collect.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collect;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }


    // 계정 만료
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // 계정 잠김
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    // 계정 유효기간
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    // 계정 정지
    @Override
    public boolean isEnabled() {

        // ex) 휴면계정
        // 현재시간 - 로그인시간 => 1년초과하면 return false

        return true;
    }
}

 

[ userDetailsService를 상속한 클래스 만들기 ]

이름 그대로 유저의 정보를 저장해주는 서비스

// 시큐리티 설정에서 loginProcessingUrl("/login")
// /login 요청이 오면 자동으로 UserDetailsService 타입으로 ioc되어있는 loadUserByUsername가 함수 실행
package com.cos.security1.config.auth;

import com.cos.security1.model.User;
import com.cos.security1.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;


// 시큐리티 설정에서 loginProcessingUrl("/login")
// /login 요청이 오면 자동으로 UserDetailsService 타입으로 ioc되어있는 loadUserByUsername가 함수 실행

@Service
public class PrincaipalDetailsService implements UserDetailsService{


    @Autowired
    private UserRepository userRepository;

    // 시큐리티 session > authentication > userDetails(principalDetails)
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // html에 꼭 "username"으로 해야함 (String username)과 매칭이 안됨
        // 바꾸고 싶다면 security config에 .usernameParameter("username2")
        // 그냥 username을 쓰자 ^^

        User userEntity = userRepository.findByUsername(username);
        if(userEntity != null){
            return new PrincipalDetails(userEntity);
        }

        return null;
    }
}

[ userRepository 에는 유저의 정보를 조회하는 부분 추가 ]

    // findBy규칙 -> username 문법
    // seelct * from user where username = #{username}
    public User findByUsername(String username);

 

spring-boot-starter-security 의존성 주입 

 

 

[ controller ]

package com.cos.security1.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class indexController {

    @GetMapping({"","/"})
    public String index(){
        // mustache 머스태치
        // 머스태치 기본폴더 src/main/resources/
        // viewResolver 설정 : templates (prefix), mustache (suffix)
        return "index"; //  src/main/resources/templates/index.mustache
    }

    @GetMapping("/user")
    public  @ResponseBody String user(){
        return "user";
    }

    @GetMapping("/admin")
    public  @ResponseBody String admin(){
        return "admin";
    }

    @GetMapping("/manager")
    public  @ResponseBody String manager(){
        return "manager";
    }

    // 스프링시큐리티가 해당주소를 낚아채버림
    // SecurityConfig 파일에서 설정으로 낚아채지 않도록 !
    @GetMapping("/login")
    public  @ResponseBody String login(){
        return "login";
    }

    @GetMapping("/join")
    public  @ResponseBody String join(){
        return "join";
    }

    @GetMapping("/joinProc")
    public @ResponseBody String joinProc(){
        return "회원가입 완료됨!";
    }
}

 

[ config ] 

package com.cos.security1.config;


import org.springframework.context.annotation.Configuration;
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
@EnableWebSecurity // 활성화 - 스프링 시큐리티 필터가 스프링 필터체인에 등록이 된다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable(); // /login으로 갈때 스프링 시큐리티가 낚아채지 않도록

        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll()// 다른주소는 OK
                .and()
                .formLogin()
                .loginPage("/login"); // 권한이 없다면 403페이지가 뜨는게 아니라 login페이지를 뜨게만들어줌

    }
}

 

[ webMvcConfiguer ]

- 머스태치 설정

- view 주소 설정

package com.cos.security1.config;

import org.springframework.boot.web.servlet.view.MustacheViewResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig  implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        MustacheViewResolver resolver = new MustacheViewResolver();
        resolver.setCharset("UTF-8");
        resolver.setContentType("text/html; charset=UTF-8");
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".html"); // .mustache가 아닌 .html로 바꿔주기 위한 작업

        registry.viewResolver(resolver); // viewResolver 등록
    }
}

 

설치한 것들

 

 

자바런타임에서 버전이랑 설정 가능

 

 

 

컨트롤 쉬프트 P 누르고 스프링 버전이랑 등등 선택해준다.

스프링 버전선택 그다음에 java

그다음에 이름 설정해줌 (ex: com.회사이름.프로젝트이름)

 

 

 

오케이오케이~

 

 

필요한 폴더들 생성해준다

main, webapp, 등등

 

어플리케이션 프로퍼티스에서 각종 설정 가능 (yml과 같음..)

spring에서의 설정파일이라고 생각하면 된다.

 

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="dao주소">
</mapper>

 

1 lib 세팅

 

pom.xml

websocket과 잭슨바인드 json을 자바의 객체로 쉽게 변경할 수 있는 gson을 넣어준다.

 

2 채팅을 위한 핸들러 클래스 정의

TextWebSocketHandler 상속해서 정의 - 접속 / 퇴장 / 메세지 전송

ace - 접속, htm - 메세지 전송, close -로그아웃 , List/Map = 저장공간

package com.aia.socket.handler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.aia.socket.domain.Message;
import com.google.gson.Gson;

public class EchoHandler extends TextWebSocketHandler {

	private static final Logger logger = LoggerFactory.getLogger(EchoHandler.class);

	private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();
	private Map<String, WebSocketSession> sessionMap = new HashMap<String, WebSocketSession>();

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		
		String chatMember = (String) session.getAttributes().get("user");

		System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>" + chatMember);
		
		
		// 저장! 둘중에 하나 사용하면 되는데, 선생님은 둘다 넣어두심
		sessionList.add(session);
		// sessionMap.put(chatMember, session);

		logger.info("{} 연결되었습니다.", session.getId()+":"+chatMember);

		System.out.println("체팅 참여자 : " + chatMember);
	}

	@Override	//메세지보내기 			//누가보냈는지에 대한 정보저장↓
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

		// 현재 로그인된 멤버
		String chatMember = (String) session.getAttributes().get("user");
		
		logger.info("{}로 부터 {}를 전달 받았습니다.", chatMember, message.getPayload());
		
		
		Gson gson = new Gson();
							//json으로부터 객체를 만듦		//이 message클래스를 기반으로 json이만들어진다.
		Message msg = gson.fromJson(message.getPayload(), Message.class); 
		// ↑ json을 java의 객체로 바꿔주는 것.		// user, to, articleId, articleOwnver(방장?), message;
		
		System.out.println(msg);
		

		// 전달 메시지
		TextMessage sendMsg = new TextMessage(gson.toJson(msg));
		
					// sessionList 모두에게, afterConnectionEstablished에서 들어오는 인간들 저장했었음
		for (WebSocketSession webSocketSession : sessionList) {
			// 상대방에게 메시지 전달
			webSocketSession.sendMessage(sendMsg);
		}
		// 자신에게 메시지 전달
		//session.sendMessage(sendMsg); 
		
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		
		// 현재 유저 - 로그아웃
		String chatMember = (String) session.getAttributes().get("user");
		sessionList.remove(session);
		logger.info("{} 연결이 끊김", session.getId()+chatMember);
		System.out.println("체팅 퇴장 : " + chatMember);
	}

}
package com.aia.socket.domain;

public class Message {

	private String user;
	private String to;
	private String articleId;
	private String articleOwner;
	private String message;

	public Message(String user, String to, String articleId, String articleOwner, String message) {
		this.user = user;
		this.to = to;
		this.articleId = articleId;
		this.articleOwner = articleOwner;
		this.message = message;
	}

	public Message() {
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public String getTo() {
		return to;
	}

	public void setTo(String to) {
		this.to = to;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String getArticleId() {
		return articleId;
	}

	public void setArticleId(String articleId) {
		this.articleId = articleId;
	}

	public String getArticleOwner() {
		return articleOwner;
	}

	public void setArticleOwner(String articleOwner) {
		this.articleOwner = articleOwner;
	}

	@Override
	public String toString() {
		return "Message [user=" + user + ", to=" + to + ", articleId=" + articleId + ", articleOwner=" + articleOwner
				+ ", message=" + message + "]";
	}



}

 

3. Spring-socket.xml 설정 파일 정의

 

설정파일 : 웹소켓 핸들러 bean 등록 

// handshake-interceptors = httpsession을 웹소켓세션으로 쓸 수 있게 해준다(?)

 

 

설정파일 : web.xml에 등록해주기!

 

 

4.

 

package com.aia.socket.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ChattingController {

	@RequestMapping("/chatting")
	public ModelAndView chat(
			ModelAndView mv,
			@RequestParam("uid") String uid,
			HttpSession session
			) {
		
		mv.setViewName("chat/chat");
		mv.addObject("user", uid);
		mv.addObject("articleId", "12345");
		mv.addObject("articleOwner", "jin");
		
		session.setAttribute("user", uid);
		
		return mv;
	}
	
}
<%@ 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>
<style>
	.text_right {
		text-align: right;
	}
	
	.text_left {
		text-align: left;
	}
	.chattingBox {
		padding : 15px;
		border : 1px solid #AAA;
		margin: 10px 0;
	}
</style>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

<!-- 웹소켓 객체를 가져올 수 있게해준다 -->
<script
	src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>

<!-- Zebra-Dialog CDN -->
<!-- <script src="resources/js/dialog/zebra_dialog.src.js"></script>
<link rel="stylesheet" href="resources/css/dialog/zebra_dialog.css" type="text/css" /> -->

</head>
<body>

	<h1>Chatting Page (id: ${user})</h1>
	<br>
	<form>
		<div>
			<div>
				<input type="text" id="message" />
				<input type="submit" id="sendBtn" value="전송" />
			</div>
			<br>
			<div class="well" id="chatdata">
				<!-- User Session Info Hidden -->
				<input type="hidden" value='${user}' id="sessionuserid">
			</div>
		</div>
	</form>
</body>

<script>
	//websocket을 지정한 URL로 연결
	var sock = new SockJS("<c:url value="/echo"/>");
	//websocket 서버에서 메시지를 보내면 자동으로 실행된다.
	sock.onmessage = onMessage;
	//websocket 과 연결을 끊고 싶을때 실행하는 메소드
	sock.onclose = onClose;
	
	
	$(document).ready(function(){
		
		$("form").submit(function() {
			console.log('send message...');
			sendMessage();
			
			$('#message').val('');
			
			$('#message').focus();
			
			
			return false;
		});
		
	});
	
	$(function() {
	});

	function sendMessage() {
		//websocket으로 메시지를 보내기
		
		var msg = {
			user : '${user}',
			to : 'jin', // 현재 페이지 작성자의 id를 작성 (강제로하나써놈예제로)
			articleId : '${articleId}',
			articleOwner : '${articleOwner}',
			message : $("#message").val()
		};
		
		sock.send(JSON.stringify(msg));
	}

	//evt 파라미터는 websocket이 보내준 데이터다.
	function onMessage(evt) { //변수 안에 function자체를 넣음.
		var data = evt.data; // 전달 받은 데이터
		
		//alert(data);
		
		msgData = JSON.parse(data); 
		
		var sessionid = null;
		var message = null;
		
		//current session id//
		var currentuser_session = $('#sessionuserid').val();
		console.log('current session id: ' + currentuser_session);
		
		var target = $('#chattingBox-1');
		
		if(target.length==0){
			$('<div id=\"chattingBox-1\" class=\"chattingBox\"></div>').html('<h3>${user} : 게시물 작성자-'+msgData.articleOwner+'</h3>').appendTo('body');
			$('#chattingBox-1').append('<hr>')
		}

			

		// 나와 상대방이 보낸 메세지를 구분하여 출력
		if (msgData.user == currentuser_session) {
			var printHTML = "<div class='well text_right'>";
			printHTML += "<div class='alert alert-info'>";
			printHTML += "<strong>[" + msgData.user + "] -> " + msgData.message
					+ "</strong>";
			printHTML += "</div>";
			printHTML += "</div>";

			$('#chattingBox-1').append(printHTML);
		} else {
			var printHTML = "<div class='well text_left'>";
			printHTML += "<div class='alert alert-warning'>";
			printHTML += "<strong>[" + msgData.user + "] -> " + msgData.message
					+ "</strong>";
			printHTML += "</div>";
			printHTML += "</div>";

			$('#chattingBox-1').append(printHTML);
		}

		console.log('chatting data: ' + data);

		/* sock.close(); */
	}

	function onClose(evt) {
		$("#data").append("연결 끊김");
	}
</script>
</html>

1-1. pom.xml에 라이브러리 추가

<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

1-2. 서블릿 리퀘스트에 빈즈 추가

	<beans:bean id="mainSender"
	class="org.springframework.mail.javamail.JavaMailSenderImpl"
	>
	
	<beans:property name="host" value="smtp.gmail.com"/>
	<beans:property name="port" value="587"/>
	<beans:property name="username" value="hyoseonjinbit@gmail.com"/>
	<beans:property name="password" value="비밀번호라서지움ㅎㅎㅎㅎ"/>
	<beans:property name="defaultEncoding" value="UTF-8"/>
	<beans:property name="javaMailProperties">
		<beans:props>
			<beans:prop key="mail.transport.protocal">smtp</beans:prop>
			<beans:prop key="mail.transport.auth">true</beans:prop>
			<beans:prop key="mail.smtp.starttls.enable">true</beans:prop>
			<beans:prop key="mail.debug">true</beans:prop>
		</beans:props>
	</beans:property>	
	</beans:bean>
	
	
	<beans:bean id="templateEmailmessage"
	class="org.springframework.mail.SimpleMailMessage"
	p:subject="회원가입을 축하합니다"
	p:text="정상적인 가입을 위해 아래링크를 클릭해주세요"/>
package com.aia.firstspring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.aia.firstspring.service.MailSenderService;

@Controller
@RequestMapping("/mail")
public class MailSenderController {
	
	@Autowired
	private MailSenderService mailService; 
	
	@RequestMapping("/simplemail")
	public void simpleMailSend() {
		
		mailService.simpleMailsend();
	}
	
	
	@Autowired
	private SimpleMailMessage templateMessage;
	
	@Autowired  
	private JavaMailSender mailsender;
	
	@RequestMapping("/simplemail2")
	public void simpleMailSend2() {
		
		mailService.mailSend("heeumheeum@naver.com");
		
		/*
		 * SimpleMailMessage message = new SimpleMailMessage(templateMessage);
		 * message.setTo("heeumheeum@naver.com");
		 * 
		 * mailsender.send(message);
		 */	
	}
	
}
package com.aia.firstspring.service;

import java.io.UnsupportedEncodingException;

import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
public class MailSenderService {

	@Autowired  
	private JavaMailSender mailsender;
	
	public boolean simpleMailsend() {
		
		boolean result =true;

		
		SimpleMailMessage message = new SimpleMailMessage();
		message.setTo("hyein4coding@gmail.com");
		message.setSubject("인정합니까?");
		message.setText("인정합니다");
		try {
			mailsender.send(message);
		}catch (MailException e) {			
			result = false;
		}
		return result;
	}

	public boolean mailSend(String toEmailAddress) {
		
		boolean result = true;
		
		MimeMessage message = mailsender.createMimeMessage();
		try {
			
			// 메일의 제목 설정
			message.setSubject("[안내] 가입축하", "UTF-8"); 
			// 메일 내용
			String htmlStr = "<h1 style=\"color:red;\">가입축하드립니다 :)</h1>";
			message.setText(htmlStr, "UTF-8", "html");
			// 보내는 사람 이메일 : gmail을 사용하는 경우에는 인증된 메일처리가 된다.
			message.setFrom(new InternetAddress("hyoseonjinbit@gmail.com"));
			// 받는 사람의 이메일  주소
			message.addRecipient(RecipientType.TO, new InternetAddress("heeumheeum@naver.com","효선쓰","UTF-8"));
			// 메일 전송
			mailsender.send(message);
			
			
		} catch (MessagingException e) {
			result=false;
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			result=false;
			e.printStackTrace();
		}
		
		return result;
	}
	

	// 받는사람의메일주소, 받는이름, 메일제목, 메일내용
	public boolean mailSend(String toEmailAddress,String name, String subject, String text) {
		
		boolean result = true;
		
		MimeMessage message = mailsender.createMimeMessage();
		try {
			
			// 메일의 제목 설정
			message.setSubject(subject, "UTF-8"); 
			// 메일내용
			message.setText(text, "UTF-8", "html");
			// 보내는 사람 이메일 : gmail을 사용하는 경우에는 인증된 메일처리가 된다.
			message.setFrom(new InternetAddress("hyoseonjinbit@gmail.com"));
			// 받는 사람의 이메일  주소
			message.addRecipient(RecipientType.TO, new InternetAddress(toEmailAddress,name,"UTF-8"));
			// 메일 전송
			mailsender.send(message);
			
			
		} catch (MessagingException e) {
			result=false;
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			result=false;
			e.printStackTrace();
		}
		
		return result;
	}
}

 

 

package com.aia.firstspring.member.service;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.aia.firstspring.member.dao.MemberDao;
import com.aia.firstspring.member.dao.MemberInterfaceDao;
import com.aia.firstspring.member.dao.MybatisMemberDao;
import com.aia.firstspring.member.domain.Member;
import com.aia.firstspring.service.MailSenderService;

@Service
public class MemberRegService {

//	@Autowired
//	private MemberDao dao;
	
//	@Autowired
//	private MybatisMemberDao dao;
	
	private MemberInterfaceDao dao;
	
	@Autowired
	private SqlSessionTemplate template;
	
	@Autowired
	private MailSenderService mailService;
	
	
	public int insertMember(Member member) {
		int result = 0;
		try {
			dao = template.getMapper(MemberInterfaceDao.class);
			result = dao.insertMember(member);
			
			String htmlStr="<h1><a href=\"http://localhost:8080/op/firstspring\">인증하기</a></h1>";
			// 메일 전송
			mailService.mailSend(member.getMemberid(), member.getMembername(), "인증확인메일", htmlStr);
		} catch (Exception e) {
			e.printStackTrace();
		}
				
		return result;
	}
	
	
	
	
	
	
	
	
	
	
}
@@ -0,0 +1,14 @@
<%@ 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>


<h1>메일발송✉✉</h1>
</body>
</html>

 

HTTP 통신 기반의 아키텍처 REST
-REST는 Representational State Transfer의 약어로 하나의 URI는 하나의 고유한 리소스를 대표하도록 설계된다는 개념.
- REST 방식은 특정한 URI는 반드시 그에 상응하는 데이터 자체라는 것을 의미. 예를 들면 /post/123은 해당 페이지의 번호의 123번이라는 고유한 의미를 가지고 설계하고, 이에 대한 처리는 GET, POST방식과 같이 추가적인 정보를 통해서 결정된다.
- REST API는 외부에서 위와 같은 방식으로 특정 URI를 통해서 사용자가 원하는 정보를 제공하는 방식.
- REST방식의 서비스 제공이 가능한 것을 Restful 하다고 표현.
- 스프링 3부터 @ResponseBody 애노테이션을 지원하면서 REST방식의 처리를 지원하고 있었으며, 스프링 4에 들어와서 @RestController가 본격적으로 적용.

 

REST API는 다음의 구성되어있다.
- 자원(RESOURCE) - URI
- 행위(Verb) - HTTP METHOD ( GET, POST, DELETE, PUT )
- 표현(Representations)

 

 

 

 

 

 

@PathVariable을 이용한 경로 변수 처리

- 경로의 특정 위치 값이 고정되지 않고 달라질 때 사용하는 것이 @PathVariable

 

 

 

 

 

 

 

@RequestBody & @ResponseBody

 

 

@RequestBody 과 @ResponseBody는 요청몸체와 응답 몸체 구현 
- @RequestBody  : JSON 형식의 요청 몸체를 자바 객체로 변환 
- @ResponseBody : 자바 객체를 JSON 이나 XML 형식의 문자열로 변환 
- Spring Framework는 HttpMessageConverter 를 이용해서 자바 객체와 HTTP 요청/응답 몸체 사이의 변환 처리

 

package com.aia.firstspring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/mc/simple")
public class SimpleConvertercontroller {
	
	
	@RequestMapping(method = RequestMethod.GET)
	public String form() {
		
		return "simple/form";
	}
	
	@RequestMapping(method = RequestMethod.POST)
	@ResponseBody
	public String simple(@RequestBody String body) {
		
		System.out.println(body + " @ResponseBody 어노태이션은 일반객체도응답처리가된다 ");
		return body;
	}
		

}
<%@ 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>

	<h1>form</h1>
	
	<form method="post">
	name : <input type="text" name="uname"><br>
	age : <input type="number" name="age"><br>
	<input type="submit">
	</form>

</body>
</html>

 

 

 

 

JAXB2를 이용한 XML 처리

 

 

package com.aia.firstspring.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.aia.firstspring.domain.GuestMessage;
import com.aia.firstspring.domain.GuestMessageList;

@Controller
public class GuestMessageController {
	
	@RequestMapping("/message/listXml") 
	@ResponseBody
	public GuestMessageList listXml() {
		return getMessageList();
	}

	private GuestMessageList getMessageList() {

		List<GuestMessage> list = new ArrayList<GuestMessage>();
		list.add(new GuestMessage(1, "안녕", new Date()));
		list.add(new GuestMessage(2, "HELLO", new Date()));
		list.add(new GuestMessage(3, "빠이", new Date()));
		return new GuestMessageList(list);
	}
	

}
package com.aia.firstspring.domain;

import java.util.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="", propOrder = {"id", "message", "regDate"})
public class GuestMessage {


	private int id;
	private String message;
	private Date regDate;
	
	
	public GuestMessage() {
	}

	public GuestMessage(int id, String message, Date regDate) {
		this.id = id;
		this.message = message;
		this.regDate = regDate;
	}
	
	
}
package com.aia.firstspring.domain;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="message-list") // <message-list></message-list>
public class GuestMessageList {
	
	
	@XmlElement(name="message")
	private List<GuestMessage> message;

	public GuestMessageList(List<GuestMessage> message) {
		this.message = message;
	}

	public List<GuestMessage> getMessage() {
		return message;
	}

	public void setMessage(List<GuestMessage> message) {
		this.message = message;
	}

	public GuestMessageList() {
	}
	
	
	

}

 

 

 

 

 

JACKSON2를 이용한 JSON 형식의 처리

 

 

잭슨 버전과 스프링 버전에 신경써서 해야함

 

 

 

package com.aia.firstspring.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.aia.firstspring.domain.GuestMessage;
import com.aia.firstspring.domain.GuestMessage2;
import com.aia.firstspring.domain.GuestMessageList2;

@Controller
public class GuestMessageController2 {
	

	@RequestMapping(value= "/message/listJson") 
	@ResponseBody
	public GuestMessageList2 listXml2() {
		return getMessageList2();
	}

	
	private GuestMessageList2 getMessageList2() {

		List<GuestMessage2> list2 = new ArrayList<GuestMessage2>();
		list2.add(new GuestMessage2(1, "안녕", new Date()));
		list2.add(new GuestMessage2(2, "HELLO", new Date()));
		list2.add(new GuestMessage2(3, "빠이", new Date()));
		return new GuestMessageList2(list2);
	}
	

}
package com.aia.firstspring.domain;

import java.util.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

public class GuestMessage2 {
	
	private int id;
	private String message;
	private Date regDate;

	public GuestMessage2() {
	}

	public GuestMessage2(int id, String message, Date regDate) {
		this.id = id;
		this.message = message;
		this.regDate = regDate;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Date getRegDate() {
		return regDate;
	}

	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}
}
	
	
package com.aia.firstspring.domain;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


public class GuestMessageList2 {

	private List<GuestMessage2> message;

	public GuestMessageList2(List<GuestMessage2> message) {
		this.message = message;
	}

	public List<GuestMessage2> getMessage2() {
		return message;
	}

	public void setMessage2(List<GuestMessage2> message) {
		this.message = message;
	}

	public GuestMessageList2() {
	}
	
	
	

}

'spring' 카테고리의 다른 글

[스프링부트] vs code 사용하기 메모  (0) 2021.03.08
[스프링] 웹소켓 : 채팅  (0) 2021.01.29
[스프링] 메일발송하기  (0) 2021.01.25
[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] jdbc  (0) 2021.01.11

- preHandle()

컨트롤러가 호출되기 전에 실행된다. handler 파라메터는 핸들러 매핑이 찾아 준 컨트롤러 빈 오브젝트다. 컨트롤러 실행 이전에 처리해야 할 작업이 있다거나, 요청정보를 가공하거나 추가하는 경우에 사용할 수 있다. 또는 요청에 요청에 대한 로그를 남기기 위해 사용하기도 한다. 리턴 값이 true 이면 핸들러 실행 체인의 다음 단계로 진행되지만, false 라면 작업을 중단하고 리턴 하므로 컨트롤러와 남은 인터셉터들은 실행되지 않는다.
– postHandle() 

컨트롤러를 실행하고 난 후에 호출된다. 이 메소드에는 컨트롤러가 돌려준 ModelAndView 타입의 정보가 제공 되서 컨트롤러 작업 결과를 참조하거나 조작할 수 있다.
–afterCompletion() 

이름 그대로 모든 뷰에서 최종 결과를 생성하는 일을 포함한 모든 작업이 모두 완료된 후에 실행된다. 요청처리 중에 사용한 리소스를 반환해주기에 적당한 메소드다.

 

핸들러 인터셉터는 하나 이상을 등록할 수 있다. preHandle() 은 인터셉터가 등록된 순서대로 실행된다. 반면에 postHandle() 과 afterCompletion() 은 preHandle() 이 실행된 순서와 반대로 실행된다.

 

 

 

HandlerInterceptor를 통한 요청 가로채기

 

 

HandlerInterceptor 인터페이스의 구현
– 핸들러 인터셉터는 HandlerInterceptor 인터페이스를 구현해서 만든다. 이 인터페이스를 구현 할 경우 사용하지 않는 메서드도 구현 해주어야 한다.
– 이러한 불편함을 줄여주기 위해 HandlerInterceptorAdaptor 클래스를 제공.
– HandlerInterceptor 인터페이스를 구현해야 하는 클래스는 HandlerInterceptorAdaptor 클래스를 상속 받은 뒤 필요한 메서드만 오버라이딩 하여 사용.

 

 

 

1. HandlerMapping에 HandlerInterceptor 설정 하기

 

 

HandlerInterceptor를 구현 한 뒤에는 <mvc:interceptors> 의 interceptors 프로퍼티를 사용해

HandlerInterceptorAdaptor 를 등록해 주면 된다.

xmlns:mvc가아니라 생략되어 있으므로 <interceptors>로 등록했다.

 

2. HandlerInterceptor 인터페이스의 구현

 

 

 

예외처리

 

 

 

 

@ExceptionHandler 어노테이션을 이용한 처리

 

– AnnotationMethodHandlerExceptionResolver 클래스는 @Controller 어노테이션이 적용된 클래스에서 @ExceptionHandler 어노테이션이 적용된 메서드를 이용해서 예외 처리한다. @ModelAttribute 에서 ExceptionHandler 에서 지정한 예외가 발생하면 @ExceptionHandler가 적용된 메서드를 이용해서 뷰를 지정.

 

 

mypage3에서 강제로 예외를 발생시켜보았다. 에러가 발생시 error/nullpoiner.jsp로 이동한다.

 

 

'spring' 카테고리의 다른 글

[스프링] 웹소켓 : 채팅  (0) 2021.01.29
[스프링] 메일발송하기  (0) 2021.01.25
[스프링] REST API / @RequestBody @ResponseBody , HttpMessageConverter  (0) 2021.01.20
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08

 

<?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.aia.op.member.dao.MemberDao">

	<!-- Member 타입의 resultMap : 로그인시 사용 -->
	<resultMap id="memberResult"
		type="com.aia.op.member.domain.Member">
		<id column="idx" property="idx" />
		<result column="memberid" property="memberid" />
		<result column="membername" property="membername" />
		<result column="password" property="password" />
		<result column="memberphoto" property="memberphoto" />
		<result column="regdate" property="regdate" />
	</resultMap>


 <!-- Member 타입인데 위랑 다르게 비밀번호 안받음 -->
 
	<resultMap id="memberListResult"
			 type="com.aia.op.member.domain.Member">
		<id column="idx" property="idx" />
		<result column="memberid" property="memberid" />
		<result column="membername" property="membername" />
		<result column="memberphoto" property="memberphoto" />
		<result column="regdate" property="regdate" />
	</resultMap>




	<!-- 회원가입 -->
	<insert id="insertMember"
		parameterType="com.aia.op.member.domain.Member">
		
		INSERT INTO member
		
		<if test="memberphoto == null">		
		(memberid, password, membername)
		VALUES 
		(#{memberid},#{password},#{membername})
		</if>
		
		<if test="memberphoto != null">
		(memberid, password, membername, memberphoto)
		VALUES 
		(#{memberid},#{password},#{membername},#{memberphoto})
		</if>
		
		
		
	</insert>
	
	
	
	

	<!-- 로그인 -->
	<select id="selectLogin" resultMap="memberResult">
		select * from member where memberid=#{param1} and password=#{param2}
	</select>


	<!-- 회원의 총 수 -->
	<select id="selectTotalCount" resultType="int">
		select count(*) from
		member
	</select>


<!-- 멤버 리스트 구하기 -->
	<select id="selectMemberList"
					parameterType="map"
					resultMap="memberListResult">

		select * from member 
		<where>
			<if test="searchParam != null">
				<if test="searchParam.searchType == 'id'">
					<include refid="searchId"/>
				</if>
				<if test="searchParam.searchType == 'name'">
					<include refid="searchName"/>
				</if>
				<if test="searchParam.searchType == 'both'">
					<include refid="searchId"/>
					<include refid="searchName"/>
				</if>
			</if>
		</where>
		
		
		limit #{index}, #{count}

	</select>
	
	
	
	<!-- 검색 시 검색 결과에 나오는 회원의 수 구하기 -->
	<select id="selectSearchMemberCount" 
	        parameterType="com.aia.op.member.domain.SearchParam"
	        resultType="int"
	        >
	        
		select count(*) from member
		
		<!-- where idx>0  -->
		
		<where>
			<if test="searchParam.searchType == 'id'">
				  <!-- memberid like	concat('%',#{keyword},'%') -->
				  <include refid="searchId"/>
			</if>
			
			<if test="searchParam.searchType == 'name'">
				 <!-- membername like	concat('%',#{keyword},'%') -->
				 <include refid="searchName"/>
			</if>
			
			<if test="searchParam.searchType == 'both'">
				 <!-- membername like	concat('%',#{keyword},'%') 				 
				 or 
				 memberid like	concat('%',#{keyword},'%') --> 
				 <include refid="searchId"/>
				 <include refid="searchName"/>
			</if>
		</where>
		
			
	</select>
	
	
<!-- 가져다가 쓸수 있는 반복적인 sql문 만들기 / 아이디찾기 이름으로찾기 -->
	<sql id="searchId">
		or memberid like	concat('%',#{searchParam.keyword},'%')
	</sql>
	
	<sql id="searchName">
	  or membername like	concat('%',#{searchParam.keyword},'%')
	</sql>
	
	
<!-- 삭제 -->
	<delete id="deleteMemberByIdx">
		delete from member where idx=#{idx}
	</delete>


<!-- IDX를 기반으로 멤버찾기 -->
	<select id="selectMemberByIdx"
	        resultMap="memberListResult">
																		<!-- no를 쓴이유는 #{idx}가 아니어도 된다는 것을 보여주기위해 -->
		select * from member where idx=#{no}
		
	</select>



	<!-- 수정하기 -->
	<update id="updateMember"
					parameterType="com.aia.op.member.domain.Member">
	
		update member 
		set membername=#{membername}, 
				password=#{password}, 
				memberphoto=#{memberphoto}
		where idx=#{idx}  
	
	</update>









</mapper>d

'spring' 카테고리의 다른 글

[스프링] 메일발송하기  (0) 2021.01.25
[스프링] REST API / @RequestBody @ResponseBody , HttpMessageConverter  (0) 2021.01.20
[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08

설정하기

 

pom.xml에 라이브러리 등록해주기.

스프링 트랜잭션은 별다른 이유가 없는한 스프링프레임워크 버전과 맞춰준다. (나는 3.1.1이었음)

 

sqlsessionfactory bean등록하기 (id=SqlSessionFactory와 SqlSessionTemplate부분)

경로 안에있는 모든 xml파일을 mapper로사용하겠다는뜻

 

아직 mapper가 없어서 warn이뜨지만 제대로 실행되는 것을 볼 수 있다.

 

 

 

SqlSessionTemplate을 이용한 DAO 구현

 

예제1)

 

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

Mapper 작성 (id=selectAll)

 

 

package com.aia.firstspring.member.dao;

import java.util.List;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.aia.firstspring.domain.Member;

@Repository
public class MybatisMemberDao {
	
	
	private String nameSpace = "com.aia.firstspring.mybatis.mapper.memberMapper";
	@Autowired
	private SqlSessionTemplate template;
	
	public List<Member> selectMemberList(){
		return template.selectList(nameSpace + ".selectAll");
	}

}

Dao 작성

이전 코드와 비교했을때 Mybatis를 이용하면 코드가 매우간결해지는 것을 볼 수 있다.

(물론 서비스에서 Dao를 바꿔줘야하는 것 잊지말자)

 

 

 

예제2)

mapper 작성

 

	public int insertMember(Member member) {
		return template.update(nameSpace+ ".insertMember", member);
	}

Dao

 

 

예제3) 외래키값 가져오기.

 

이렇게 keyproperty를 이용하면 idx값을 받아올 수 있다.

 

 

자동 매퍼 생성 기능을 이용한 DAO 구현

 

package com.aia.firstspring.member.dao;

import java.util.List;

import com.aia.firstspring.domain.Member;

public interface MemberInterfaceDao {

	
	//abstract public 생략	
	List<Member> selectMemberList();
	int insertMember(Member member);
	int totalCount();
}

인터페이스생성!

MyBatis는 인터페이스를 이용해서 런타임에 매퍼 객체를 생성하는 기능을 제공한다.

 

마찬가지로 서비스에서 Dao를 바꿔줘야하는 것 잊지말아야하고

template를 주입받아야 한다.

 

Mapper

mapper에서는 인터페이스 안에 있는 메서드와 이름을 같에 만들어 주는 것이 중요하다.

이름이 같아야 자동으로 인식되기 때문이다 :)

 

'spring' 카테고리의 다른 글

[스프링] REST API / @RequestBody @ResponseBody , HttpMessageConverter  (0) 2021.01.20
[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08

mysql / hikariCP / springjdbc라이브러리를 pom.xml에 등록

 

스프링은 버전에 맞춰서 라이브러리를 추가해주는데,

스프링 버전이 바뀔때마다 자동으로 바뀌게 하려면 이런식으로 값을 넣어주면 된다.

 

 

데이터 베이스 / JdbcTemplate 클래스 빈 등록 / root-context.xml

package com.aia.firstspring.domain;

import java.sql.Timestamp;
import java.util.Date;

public class Member {
	
	private int idx;
	private String memberid;
	private String password;
	private String membername;
	private String memberphoto;
	private Timestamp regdate;
	public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	public String getMemberid() {
		return memberid;
	}
	public void setMemberid(String memberid) {
		this.memberid = memberid;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getMembername() {
		return membername;
	}
	public void setMembername(String membername) {
		this.membername = membername;
	}
	public String getMemberphoto() {
		return memberphoto;
	}
	public void setMemberphoto(String memberphoto) {
		this.memberphoto = memberphoto;
	}
	public Timestamp getRegdate() {
		return regdate;
	}
	public void setRegdate(Timestamp regdate) {
		this.regdate = regdate;
	}
	
	
	public Date getToDate() { // ${member.toDate}
		return new Date(getRegdate().getTime());
		
	}
	
	
	
	
	@Override
	public String toString() {
		return "Member [idx=" + idx + ", memberid=" + memberid + ", password=" + password + ", membername=" + membername
				+ ", memberphoto=" + memberphoto + ", regdate=" + regdate + "]";
	}
	
	

}

 

 

 

예제1) 회원리스트출력

 

Memberdao [@Reporitory]로 Dao를 등록해준다 (bean등록안해도 간단하게 등록가능)

package com.aia.firstspring.member.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.aia.firstspring.domain.Member;


@Repository
public class MemberDao {
	
	
	@Autowired
	private JdbcTemplate template;

	
	// jdbctemplate template 인스턴스를 주입
	// 1. 생성자 주입방식
	// 2. 프로퍼티 주입 방식
	// 3. 자동주입
	
	// 생성자를 이용한 객체 주입
	/*
	 * public MemberDao(JdbcTemplate t) { template = t;
	 * System.out.println("MemberDao 인스턴스 생성");
	 * 
	 * }
	 */
	
	public List<Member> selectMemberList() {
		String sql="select*from member order by memberid";
		
			return template.query(sql, new RowMapper<Member>() {

				@Override
				public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
					Member member = new Member();
					member.setIdx(rs.getInt("idx"));
					member.setMemberid(rs.getString("memberid"));
					member.setMembername(rs.getString("membername"));
					member.setPassword(rs.getString("password"));
					member.setMemberphoto(rs.getString("memberphoto"));
					member.setRegdate(rs.getTimestamp("regdate"));
					return member;
				}
			}	
				
			);
	}
	
	public int selectTotalCount() {
		String sql = "select count(*) from member";
		return template.queryForObject(sql, Integer.class);
	}
}

 

 

MemberListController

package com.aia.firstspring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.aia.firstspring.member.service.MemberListService;

@Controller
public class MemberListController {
	
	@Autowired
	private MemberListService listService;
	
	
	@RequestMapping("/member/list")
	public String getMemberList(Model model) {	
		
		model.addAttribute("members",listService.getMemberList());
		model.addAttribute("memberCnt", listService.getMemberTotalCount());
		
		return "member/list";		
	}

}

MemberListService

package com.aia.firstspring.member.service;

import java.util.List;

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

import com.aia.firstspring.domain.Member;
import com.aia.firstspring.member.dao.MemberDao;

@Service
public class MemberListService {
	
	@Autowired
	MemberDao dao;
	
	/*
	 * public MemberListService(MemberDao dao) { this.dao=dao; }
	 */
	
	// 회원목록 반환 메서드
	public List<Member> getMemberList(){		
		return dao.selectMemberList();
	}
	
	// 회원수 몇명인지 int로 반환해주는 메서드
	public int getMemberTotalCount() {		
		return dao.selectTotalCount();
	}

}

view > list.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>Member List</title>
</head>
<body>

	<h1>회원리스트</h1>

	<hr>
	${members}
	
	<h3>총회원수 ${memberCnt}</h3>

	<table>
		<tr>
			<th>idx</th>
			<th>id</th>
			<th>password</th>
			<th>name</th>
			<th>사진</th>
			<th>가입일</th>
		</tr>
		
		<c:forEach items="${members}" var="member"> 
			<tr>
				<td>${member.idx}</td>
				<td>${member.memberid}</td>
				<td>${member.password}</td>
				<td>${member.membername}</td>
				<td>${member.memberphoto}</td>
				<td>${member.toDate}</td>
			</tr>
		</c:forEach>
		
	</table>

</body>
</html>

 

 

 

 

예제2 ) 회원가입하기

 

컨트롤러 > 회원가입 성공시 리스트출력으로

package com.aia.firstspring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.aia.firstspring.domain.Member;
import com.aia.firstspring.member.service.MemberRegService;

@Controller
@RequestMapping("/member/reg")
public class MemberRegController {
	
	@Autowired
	private MemberRegService regService;

	@RequestMapping(method = RequestMethod.GET)
	public String getRegForm() {
		return "member/regForm";
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String memberReg(Member member, Model model) {
		
		int resultCnt = regService.insertMember(member);
		String view="member/reg";
		model.addAttribute("resultCnt", resultCnt);
		
		if(resultCnt==1) {
			view= "redirect:/member/list";
		}
		return view;
	}
}

서비스

package com.aia.firstspring.member.service;

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

import com.aia.firstspring.domain.Member;
import com.aia.firstspring.member.dao.MemberDao;

@Service
public class MemberRegService {

	@Autowired
	private MemberDao dao;

	public int insertMember(Member member) {
		int result=0;
		try {
			result = dao.insertMember(member);
		}catch (Exception e){
			e.printStackTrace();
			
		}
		return result;
		
	}
}

MemberDao에 회원가입 메서드 추가

	public int insertMember(Member member) {
		//그냥 세개만 하기로 했음 ㅎ..
		String sql="insert into member (memberid, membername, password) values (?,?,?)";
		return template.update(sql, member.getMemberid(), member.getMembername(), member.getPassword());
		
	}

 

 

RegForm / name속성 맞춰줄것

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입 폼</title>
</head>
<body>

<h1>회원 가입 폼</h1>
<form method="post">
아이디 <input type="text" name="memberid"><br>
비밀번호 <input type="password" name="password"><br>
이름 <input type="text" name="membername"><br>
<input type="submit">


</form>
</body>
</html>

reg / 가입 실패시 나오는 창

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입 폼</title>
</head>
<body>

<h1>회원 가입 실패</h1>
${resultCnt}


</form>
</body>
</html>

'spring' 카테고리의 다른 글

[스프링] 인터셉터 / intercepter  (0) 2021.01.15
[스프링] mapper / CRUD  (0) 2021.01.15
[스프링] mybatis  (0) 2021.01.12
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08
[스프링] DI / xml 설정파일 / 어노테이션  (0) 2021.01.06

 

 

MultipartResolover 설정

 

Multipart 지원 기능을 사용하려면 MultipartResolver를 스프링 설정 파일에 등록해야 한다.

Multipart 형식으로 데이터가 전송된 경우 해당 데이터를 스프링 MVC에서 사용 가능 하도록 변환해준다.

Commons FileUpload API 라이브러리를 이용해서 Multipart를 처리해 준다.

CommonsMultipartResolver를 MultipartResolver로 사용하기 위해서는 “multipartResolver” 이름의 빈으로 등록

 

 

파일업로드의 방법

1.@Requestparam 애노테이션을 이용한 업로드 파일 접근

2. MultipartHttpServletRequest 이용한 업로드 파일 접근

3. 커맨드 객체를 통한 업로드 파일 접근

MultipartRequest 인터페이스가 제공하는 메소드

 

입력받는 uploadForm.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>

<h1>파일업로드</h1>
<hr>
<h3>@RequestParam 이용한 파일 업로드</h3>
<form action="upload1" method="POST" enctype="multipart/form-data">
 
	 <!-- /fisrtspring/upload/uploadForm > /fisrtspring/upload/upload -->
	 
	 학번 : <input type="text" name="sn"><br>
	 리포트 파일 : 	<input type="file" name="report"><br>
	 <input type="submit">
	
</form>

<hr>
<h3>MultipartHttpServletRequest를 이용한 파일 업로드</h3>
<form action="upload2" method="POST" enctype="multipart/form-data">
	 
	 학번 : <input type="text" name="sn"><br>
	 리포트 파일 : 	<input type="file" name="report"><br>
	 <input type="submit">
	
</form>



<hr>
<h3>커맨드 객체를 통한 업로드 파일 접근</h3>
<form action="upload3" method="POST" enctype="multipart/form-data">
	 
	 학번 : <input type="text" name="sn"><br>
	 리포트 파일 : 	<input type="file" name="report"><br>
	 <input type="submit">
	
</form>

</body>
</html>

컨트롤러 FileuploadController.java

package com.aia.firstspring.controller;

import java.io.File;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.aia.firstspring.domain.ReportUploadRequest;

@Controller
public class FileuploadController {

	final String uri = "/uploadfile";

	@RequestMapping("/upload/uploadForm")
	public String uploadForm() {
		return "upload/uploadForm";
	}

	
	
	@RequestMapping("/upload/upload1")
	public String upload1(
			@RequestParam("sn") String sn,
			@RequestParam("report") MultipartFile report, 
			Model model,
			HttpServletRequest request) throws IllegalStateException, IOException {

		System.out.println(report.getOriginalFilename());

		model.addAttribute("sno", sn);
		model.addAttribute("reportFile", report.getOriginalFilename());
		
		// 파일의 저장
		report.transferTo(getFile(request, uri, report.getOriginalFilename()));

		return "upload/uploadComplete";
	}

	
	
	
	
	@RequestMapping("/upload/upload2")
	public String upload2(MultipartHttpServletRequest request, Model model) throws IllegalStateException, IOException {

		String sn = request.getParameter("sn");
		MultipartFile report = request.getFile("report");

		System.out.println(report.getOriginalFilename());

		model.addAttribute("sno", sn);
		model.addAttribute("reportFile", report.getOriginalFilename());
		
		// 파일 저장
		report.transferTo(getFile(request, uri, report.getOriginalFilename()));

		return "upload/uploadComplete";
	}
	
	
	

	@RequestMapping("/upload/upload3")
	public String upload3(
			ReportUploadRequest uploadrequest,
			Model model,
			HttpServletRequest request) throws IllegalStateException, IOException {

		System.out.println(uploadrequest.getReport().getOriginalFilename());

		model.addAttribute("sno", uploadrequest.getSn());
		model.addAttribute("reportFile", uploadrequest.getReport().getOriginalFilename());
		
		// getReport = 멀티파트파일
		uploadrequest.getReport().transferTo(getFile(request, uri,uploadrequest.getReport().getOriginalFilename())); 

		return "upload/uploadComplete";
	}


	
	
	
	/*
	  private String getRealpath(HttpServletRequest request, String uri) { return
	  request.getSession().getServletContext().getRealPath(uri); }
	 */

	
	// File 객체를 생성해서 반환
	private File getFile(HttpServletRequest request, String uri, String fileName) {
		String rpath = request.getSession().getServletContext().getRealPath(uri);
		File newFile = new File(rpath, fileName);
		return newFile;
	}
}

커맨드 객체를 이용하기 위한 ReportUploadRequest.java

package com.aia.firstspring.domain;

import org.springframework.web.multipart.MultipartFile;

public class ReportUploadRequest {
	
	private String sn;
	private MultipartFile report;
	
	public String getSn() {
		return sn;
	}
	public void setSn(String sn) {
		this.sn = sn;
	}
	public MultipartFile getReport() {
		return report;
	}
	public void setReport(MultipartFile report) {
		this.report = report;
	}

	
}

 

결과 view / uploadeComplete.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>

<h1> 학생 1 학번 : ${sno} , 리포트 파일 : ${reportFile}</h1>
<img alt="레포트이미지" src="../uploadfile/${reportFile}">

</body>
</html>

 

 

 

컨트롤러 구현

 

 

@Controller 애노테이션 이용을 권장하며,

@Controller & @RequestMapping 는 구현을 위한 필수 애노테이션이다.

@Controller Controller 클래스 정의 
@RequestMapping HTTP요청 URL을 처리할 Controller 메소드 정의 
@RequestParam HTTP 요청에 포함된 파라미터 참조 시 사용 
@ModelAttribute HTTP 요청에 포함된 파라미터를 모델 객체로 바인딩

                                 @ModelAttribute의 ‘name’으로 정의한 모델 객체를 다음 View에게 사용 가능

 

 

 

문법

1. 요청 URL만 선언할 경우

@RequestMapping("/요청url")

2. 요청방식을 지정한 경우

@RequestMapping( value="/요청url" method=RequestMethod.메서드방식(ex)get/post)

 

Controller의 처리 결과를 보여줄 View 지정 방법 / 메소드의 반환 값에 따른 view page지정 방법

1. ModelAndView인 경우

setViewName() 메소드 파라미터로 설정

2. String인 경우

메소드의 리턴 값

 

 

 

예제

 

RequestMapping 예제 - 요청방식 지정에 따른 경우 

package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login() {

			ModelAndView mav = new ModelAndView();
			mav.setViewName("/member/login"); // 로그인 되었을 때 보이는 페이지 -> mapping에 밸류가 동일해서 오류 생김
			return mav;
		}

	}

 

 

 

사용자의 파라미터값을 받는 방법
1. HttpServletRequest 객체 이용
2. @RequestParam(폼의 네임속성)
3. 커맨드 객체(Beans) 이용

 

 

 

@RequestParam 예제 = @RequestParam(폼의 네임속성) 

package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login(
				@RequestParam("uid") String uid,
				@RequestParam("pw") String pw) {
			//리퀘스트파람이 파라미터를 받아올 수 있게 해준다.

			ModelAndView mav = new ModelAndView();
			mav.setViewName("/member/login"); // 로그인 되었을 때 보이는 페이지 -> mapping에 밸류가 동일해서 오류 생김
			mav.addObject("uid", uid);
			mav.addObject("pw", pw);
			
			return mav;
		}

	}

.

 

HttpServletRequest = HttpServletRequest 객체 이용 

 

package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login(
				HttpServletRequest request) {

			
			String userId = request.getParameter("uid");
			String userPw = request.getParameter("pw");
			
			ModelAndView mav = new ModelAndView();
			mav.addObject("userId", userId);
			mav.addObject("userPw",userPw);
			
			return mav;
		}

	}

 

커맨드 객체 = (Beans) 이용 

이때 객체간의 파라미터 이름이 같아야 한다!!!!!!

package com.aia.firstspring.member.domain;

public class LoginRequest {

	
	// 변수의 이름이 form에있는 name과 같아야 한다.
	String uid;
	String pw;
	
	public String getUid() {
		return uid;
	}
	public void setUid(String uid) {
		this.uid = uid;
	}
	public String getPw() {
		return pw;
	}
	public void setPw(String pw) {
		this.pw = pw;
	}
	@Override
	public String toString() {
		return "LoginRequest [uid=" + uid + ", pw=" + pw + "]";
	}
	
	
}
package com.aia.firstspring.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.aia.firstspring.member.domain.LoginRequest;

@Controller
@RequestMapping("/member/login")
public class memberLoginController {
	//사용자의 요청 url 처리해야될 기능, 메서드를 바인딩 하는 것이 컨트롤러다.
	
	// @RequestMapping(value = "/member/login", method = RequestMethod.GET)
		@RequestMapping(method = RequestMethod.GET)
		public ModelAndView getLoginForm() {
			return new ModelAndView("member/loginForm"); // setViewName과 동일, 
		}
		
		// @RequestMapping(value = "/member/login", method = RequestMethod.POST)
		@RequestMapping(method = RequestMethod.POST)
		public ModelAndView login(
				HttpServletRequest request,
				LoginRequest loginRequest) {
			
			// login("cool","1111")
			System.out.println(loginRequest);
			
			String userId = request.getParameter("uid");
			String userPw = request.getParameter("pw");
			
			ModelAndView mav = new ModelAndView();
			mav.addObject("userId", userId);
			mav.addObject("userPw", userPw);
			//mav.addObject("loginRequest", loginRequest); 
			//안해도 공유가 됨 변수이름은 클래스 이름의 앞글자를 소문자로 바꾼 것으로 됨
			
			return mav;
		}

	}

 

 

 

 

MVC : List 타입의 프로퍼티 바인딩 처리하기 예제

 

 

아이템 목록 : OrderItem.java

package com.aia.firstspring.domain;

public class OrderItem {
	
	private String itemId;
	private String number;
	private String remark;
	public String getItemId() {
		return itemId;
	}
	public void setItemId(String itemId) {
		this.itemId = itemId;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
	@Override
	public String toString() {
		return "OrderItem [itemId=" + itemId + ", number=" + number + ", remark=" + remark + "]";
	}
	
	

}

 

주소 목록 : Address.java

package com.aia.firstspring.domain;

public class Address {
	
	private String zipcode;
	private String address1;
	private String address2;
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public String getAddress1() {
		return address1;
	}
	public void setAddress1(String address1) {
		this.address1 = address1;
	}
	public String getAddress2() {
		return address2;
	}
	public void setAddress2(String address2) {
		this.address2 = address2;
	}
	
	@Override
	public String toString() {
		return "Address [zipcode=" + zipcode + ", address1=" + address1 + ", address2=" + address2 + "]";
	}
	
	

}

 

orderCommand.java

/ 커맨드는 이걸루 사용 

/ 주소랑 상품 묶어줌

package com.aia.firstspring.domain;

import java.util.List;

public class orderCommand {
	
	private List<OrderItem> orderItems; 
	private Address address;
	public List<OrderItem> getOrderItems() {
		return orderItems;
	}
	public void setOrderItems(List<OrderItem> orderItems) {
		this.orderItems = orderItems;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "orderCommand [orderItems=" + orderItems + ", address=" + address + "]";
	}
	
	

}

 

컨트롤러 OrderControoler.java

GET / POST 타입 방식에 따른 리퀘스트맵핑

@ModelAttribute 애노테이션을 사용하여 모델명을 설정 (uo로 줄여줌)

package com.aia.firstspring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.aia.firstspring.domain.orderCommand;

@Controller
@RequestMapping("/order/order")
public class OrderController {
	
	@RequestMapping(method = RequestMethod.GET)
	public String getOrderForm() {
	    	return "order/orderForm";
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String orderComplete(@ModelAttribute("uo") orderCommand order) {
		System.out.println(order);
		return "order/orderComplete";
	}

}

 

[VIEW-1]

입력받을 폼 > orderForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>주문</title>
</head>
<body>

	<h1>주문 폼</h1>
	<form method="post">
		<table border="1">
			<tr>
				<td rowspan="3">상품-1</td>
				<td>ID</td>
				<td><input type="text" name="orderItems[0].itemId"></td>
			</tr>
			<tr>
				<td>개수</td>
				<td><input type="number" name="orderItems[0].number"></td>
			</tr>
			<tr>
				<td>주의</td>
				<td><input type="text" name="orderItems[0].remark"></td>
			</tr>
			<tr>
				<td rowspan="3">상품-2</td>
				<td>ID</td>
				<td><input type="text" name="orderItems[1].itemId"></td>
			</tr>
			<tr>
				<td>개수</td>
				<td><input type="number" name="orderItems[1].number"></td>
			</tr>
			<tr>
				<td>주의</td>
				<td><input type="text" name="orderItems[1].remark"></td>
			</tr>
			<tr>
				<td rowspan="3">상품-3</td>
				<td>ID</td>
				<td><input type="text" name="orderItems[2].itemId"></td>
			</tr>
			<tr>
				<td>개수</td>
				<td><input type="number" name="orderItems[2].number"></td>
			</tr>
			<tr>
				<td>주의</td>
				<td><input type="text" name="orderItems[2].remark"></td>
			</tr>
			<tr>
				<td rowspan="3">주소</td>
				<td>우편번호</td>
				<td><input type="text" name="address.zipcode"></td>
			</tr>
			<tr>
				<td>주소1</td>
				<td><input type="text" name="address.address1"></td>
			</tr>
			<tr>
				<td>주소2</td>
				<td><input type="text" name="address.address2"></td>
			</tr>
			<tr>
				<td></td>
				<td><input type="submit"></td>
				<td></td>
			</tr>
		</table>

	</form>

</body>
</html>

[VIEW-2]

결과출력 > orderComplete.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>

	<h1>주문정보</h1>
	
	<h3>상품 주문 정보</h3>
	
	<c:forEach items="${uo.orderItems}" var="oi">
		<div>
			상품 ID : ${oi.itemId} / 개수 : ${oi.number}개 / 주의사항 : ${oi.remark} 	
		</div>	
	</c:forEach>
	
	<h3>배송지</h3>
	<div>
	
		우편번호 : ${uo.address.zipcode}
		주소1 :  ${uo.address.address1}
		주소2 :  ${uo.address.address2}
	</div>
	
</body>
</html>

 

1단계 – client의 요청을 받을 DispatcherServlet 을 web.xml 파일에 설정

 

ContextLoaderListener

- 디스패쳐서블릿의 부모(모든서블릿에 공통적용) / 디스패쳐서블릿 여러개 설정시 필수로 리스너 설정

 

DispatcherServlet / 서블릿매핑

- url패턴의 / 로 해줌. 보통 학원 예제에서는 .do로 많이 나온 부분

/ <- 로 요청되는 모든 client 의 요청을 DispatcherServlet이 처리하도록 요청

/ 이때 servlet-context.xml 이라는 이름의 Spring 설정 파일을 사용하도록 설정

 

2단계 – 컨트롤러 구현 및 설정 추가 하기 

 

컨트롤러 구현

@Controller – Spring MVC의 controller 를 구현한 클래스로 지정

@RequestMapping –/hello 라는 url값으로의 요청을 처리할 메소드 지정

 

설정파일에 등록 / 생략가능(여기선생략함)

servlet-context.xml 

 

package com.aia.firstspring.controller;

import java.util.Calendar;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;


//컨트롤 클래스라고 알려주는 어노테이션 > 이걸 해주어야 handler mapping에 등록
@Controller 
public class HelloController {
	
	// 이 메서드는 프론트컨트롤러 쪽으로 Viewname을 반환해야 한다.
	// 반환 타입은 ModelAndView를 이용해서 반환하자.
	@RequestMapping("/hello")
	public ModelAndView hello() {
		ModelAndView mav = new ModelAndView();
		
		// prefix suffix를 제외한 이름 /WEB-INF/views/member/hello.jsp -> member/hello
 		mav.setViewName("member/hello");
 		mav.addObject("greeting", greeting());
		
		return mav;
	}

	private String greeting() {
		String result = "안녕!";
		
		int nowTime = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if(nowTime>=6 && nowTime <= 10) {
			result="좋은 아침";
		} else if(nowTime >= 12 && nowTime<=15) {
			result="맛점";
		} else if(nowTime >=18 && nowTime<=22) {
			result="굿밤";
		}
		
		return result;
	}

}

 

 

3단계 – 설정파일에 viewResolver 설정 추가하기

이부분이 viewResolver

Context 설정 추가

/ namespace에서 context 추가 필수

/ 빈 설정

/ 기본패키지를 컨트롤러로 연결시켜줌

 

 

3.5단계 -  필요하다면 핸들러매핑(의존성주입)


4단계 – JSP를 이용한 View 영역의 코드 작성 


5단계 – 실행

 

우리가 보던 인터넷 사이트처럼 주소가 깔끔해짐 .jsp 이런거 없어졌다!

 

 

 

 

 

 

의존성 주입

 

 

Spring Framework가 지원하는 핵심 기능으로 객체 사이의 의존 관계가 객체 자신이 아닌 외부(조립기)에 의해 설정된다. 외부 조립기는 xml 설정 파일을 기반으로 의존을 설정한다.

 

package member.dao;

public interface Dao {
	
	// public abstract void insert();
	
	void insert();
	void select();
	void delete();
	void update();
}
package member.dao;

public class MemberDao implements Dao {

	@Override
	public void insert() {
		System.out.println("회원 정보 데이터베이스 저장");

	}

	@Override
	public void select() {
		System.out.println("회원 정보 검색");
	}

	@Override
	public void delete() {
		System.out.println("회원 정보 삭제");

	}

	@Override
	public void update() {
		System.out.println("회원 정보 수정");
	}

}

 

 

생성자 타입의 주입방식

 

package member.service;

import member.dao.Dao;

public class MemberRegService implements MemberService {

	// Dao dao = new MemberDao(); // 의존성이 높은 코드이므로 X
	
	
	/* 생성자 방식 */
	
	private Dao dao; // 주입받아야하는 참조변수
	
	// 생성자를 통해서 Dao타입의 인스턴스를 주입받는다.
	// Dao dao = new MemberDao(); -> 다형성.
	public MemberRegService(Dao dao) {
		this.dao = dao;
	}
	
	@Override
	public Object process() {
		System.out.println("MemberRegService 실행");
		dao.insert();
		
		return null;
	}
	
	

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- MemberDao를 Bean(인스턴스)으로 등록 -->
	<bean
	id="memberDao"
	class="member.dao.MemberDao"
	>
	</bean>
	
	<!-- MemberRegService bean으로등록 -->
	<bean id="memberRegService" 
		class="member.service.MemberRegService">
	<!-- <constructor-arg ref="memberDao"/> -->
	<constructor-arg>
		<ref bean="memberDao"/>
	</constructor-arg>
	</bean>
    
</beans>

 

 

프로퍼티 타입의 주입방식

 

package member.service;

import member.dao.Dao;

public class MemberInfoService implements MemberService{
	
	/* 프로퍼티 타입 */
	Dao dao;
	
	// 프로퍼티 타입의 주입 방식 : setter 메소드 정의가 필요하다
	public void setDao(Dao dao) {
		this.dao = dao;
	}
	
	
	
	
	@Override
	public Object process() {
		System.out.println("MeberInfoService 실행");
		dao.select();
		return null;
	}

}
 <!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService" class="member.service.MemberInfoService">
 <!-- <property name="dao" ref="memberDao"></property> -->
 <property name="dao">
 		<ref bean="memberDao"/>
 </property>

 

MemberMain 실행

package member.main;

import org.springframework.context.support.GenericXmlApplicationContext;

import member.service.MemberInfoService;
import member.service.MemberRegService;

public class MemberMain {

	public static void main(String[] args) {

		
		//1. Spring 컨테이너 생성
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appCtx.xml");
	
		//2. MemberRegService 객체가 필요
		MemberRegService regService = ctx.getBean("memberRegService", MemberRegService.class);

		//3. MemberRegService 프로세스 메서드 실행
		regService.process();
		
		//4. MemberinfoService 객체가 필요
		MemberInfoService infoService = ctx.getBean("memberInfoService", MemberInfoService.class);
		
		//5. MemberInfoService 프로세스 메서드 실행
		infoService.process();
	}

}

 

xml 설정파일

 

1. XML 네임스페이스를 이용한 프로퍼티 설정

 <!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService" class="member.service.MemberInfoService">
 <!-- <property name="dao" ref="memberDao"></property> -->
 <property name="dao">
 		<ref bean="memberDao"/>
 </property>
 
 
 
 ↓ 아래처럼 간결해짐
 	<!-- 프로퍼티 방식에서 p를 사용하면 속성을 사용하지 않고 한 줄 처리가 가능 -->	
    

<!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService" class="member.service.MemberInfoService"
 	p:dao-ref="memberDao">

 </bean>
</beans>

 

2. 의존관계 설정 : 임의 빈 객체 전달

 <bean id="memberInfoService" class="member.service.MemberInfoService">
 <!-- <property name="dao" ref="memberDao"></property> -->
 <property name="dao">
 		<bean class="member.dao.MemberDao"/>
 </property>
 

 

3. 여러개의 xml 사용 / 두 개 이상의 설정파일 사용하기 > import 이용

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<import resource="classpath:appCtx4_1.xml"/>
<import resource="classpath:appCtx4_2.xml"/>

</beans>

 

 

 

 

 

DI - 의존관계자동설정

 

 

 

 

빈 객체 범위

 

xml에서 scope 설정

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- MemberDao를 Bean(인스턴스)으로 등록 -->
	<bean
	id="memberDao"
	class="member.dao.MemberDao"
	>
	</bean>
	
	<!-- MemberRegService bean으로등록 -->
	<bean id="memberRegService" 
				class="member.service.MemberRegService"
				scope="prototype"
				>	
	<constructor-arg>
		<ref bean="memberDao"/>
	</constructor-arg>
	</bean>
	
 
 <!-- 멤버인포서비스 Bean등록 -->
 <bean id="memberInfoService"
 			class="member.service.MemberInfoService"
 			scope="singleton">
 <property name="dao">
 		<bean class="member.dao.MemberDao"/>
 </property>
 
 </bean>
</beans>
package member.main;

import org.springframework.context.support.GenericXmlApplicationContext;

import member.dao.Dao;
import member.service.MemberInfoService;
import member.service.MemberRegService;

public class MemberMain2 {

	public static void main(String[] args) {

		
		//1. Spring 컨테이너 생성
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appCtx5.xml");
		
		

		Dao dao1 = ctx.getBean("memberDao", Dao.class);
		Dao dao2 = ctx.getBean("memberDao", Dao.class);
		
		// 아무 처리도 하지않으면 기본적으로 싱글톤이다.
		System.out.println("dao1참조변수 == dao2참조변수 ? " +(dao1==dao2));
		
		//2. MemberRegService 객체가 필요
		MemberRegService regService1 = ctx.getBean("memberRegService", MemberRegService.class);
		MemberRegService regService2 = ctx.getBean("memberRegService", MemberRegService.class);
		
		// 프로포타입이므로 false
		System.out.println("regService1==regService2 ? " + (regService1==regService2));
		
		
		//4. MemberinfoService 객체가 필요
		MemberInfoService infoService1= ctx.getBean("memberInfoService", MemberInfoService.class);
		MemberInfoService infoService2= ctx.getBean("memberInfoService", MemberInfoService.class);
		// 싱글톤타입이므로 true > 둘의참조변수가같다
		System.out.println("infoService1==infoService2 ? " + (infoService1==infoService2));
		
		
	}

}

 

.

 

 

 

애노테이션 기반 설정

JDK5 버전부터 추가된 것으로 메타데이터를 XML등의 문서에 설정하는 것이 아니라 소스 코드에 “@애노테이션”의 형태로 표현하며 클래스, 필드, 메소드의 선언부에 적용 할 수 있는 특정 기능이 부여된 표현법이다. 프레임워크들이 활성화 되고 애플리케이션 규모가 커질수록 XML 환경 설정은 복잡해지는데, 이러한 어려움을 개선시키기 위하여 자바 파일에 애노테이션을 적용해서 코드를 작성함으로써 개발자가 설정 파일에 작업하게 될 때 발생시키는 오류의 발생 빈도를 낮춰주기도 한다.

 

 

Java 에서 이미 정의되어 있는 애노테이션


@Override - 메소드가 오버라이드 됐는지 검증.

                 부모 클래스 또는 구현해야 할 인터페이스에서 해당 메소드를 찾을 수 없다면 컴파일 오류. 
@Deprecated - 메소드를 사용하지 말도록 유도. 만약 사용한다면 컴파일 경고. 
@SuppressWarnings - 컴파일 경고를 무시. 
@SafeVarargs - 제너릭 같은 가변인자 매개변수를 사용할 때 경고를 무시.(자바7 이상) 
@FunctionalInterface - 람다 함수등을 위한 인터페이스를 지정.

                               메소드가 없거나 두 개 이상 되면 컴파일 오류.(자바 8이상)

 

 

@Autowired 애노테이션을 이용한 의존 자동 주입

 

 

xml 파일에서 annotation-config.

이전 코드보다 훨신 간결하게 프로퍼티나 생성자 부분 없이 깔끔해졌다.

 

 

 

@Autowired 애노테이션으로 인해 코드가 더깔끔해짐 (위-애노테이션 / 아래-프로퍼티&생성자방식)

 

 

@Qualifier 애노테이션을 이용한 의존 객체 선택

 

package member.dao;

public class GuestDao implements Dao {

	@Override
	public void insert() {
		System.out.println("게스트 회원 정보 데이터베이스 저장");

	}

	@Override
	public void select() {
		System.out.println("게스트  회원 정보 검색");
	}

	@Override
	public void delete() {
		System.out.println("게스트  회원 정보 삭제");

	}

	@Override
	public void update() {
		System.out.println("게스트 회원 정보 수정");
	}

}

memberDao를 복사해서 GuestDao를 만들어준 뒤 실행하면 dao가 두개라서 에러가 난다.

 

Qualifier를 이용해서 value값을 설정해주고 클래스에서 Qulifier 어노테이션으로 지정해준 후 Main 실행

 

@Autowired 의 필수 여부 지정

 

주석처리 하니 Dao가 없어서 에러가난다 (당연..)

 

없더라도 인스턴스는 생성되도록 한다.

대부분은 꼭 있어야하는 Dao같은 상황에 사용하지만, 존재의 유무를 확인할 때 등등 정리해서 쓰면 좋다.

 

 

 

@Resource 애노테이션을 이용한 자동 의존 주입

 

id를 name으로 써서 구별한다.

그러나 타입으로 구별하는 @autowired를 더 자주사용한다.

타입을 맞추는 것이 더 정확하고 에러가 덜 나기 때문이래나 뭐래나.. 암튼 그렇다!

자동 주입과 명시적 의존 주입 설정이 함께 사용되는 경우 명시적인 의존 주입 설정이 우선한다

 

.

 

 

 

 

[Spring] 의존객체 자동 주입(Automatic Dependency Injection), @Autowired, @Resource, @Inject

| 의존객체 자동 주입(Automatic Dependency Injection) 의존 객체 자동 주입(Automatic Dependency Injection)은 스프링 설정파일에서  혹은  태그로 의존 객체 대상을 명시하지 않아도 스프링 컨테이너가 자..

xzio.tistory.com

 

'spring' 카테고리의 다른 글

[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08
[스프링] 자바 프로젝트를 메이븐 기반의 프로젝트로 변환하기  (0) 2021.01.06
[스프링] 기본 설정  (0) 2021.01.05
[스프링] 설치  (0) 2021.01.05

자바 프로젝트를 메이븐 기반의 프로젝트로 변환하기

 

자바 프로젝트 생성 후 Convert to Maven Project > pom.xml이 생성된다.

 

mvnrepository.com/artifact/org.springframework/spring-context/3.1.1.RELEASE

에서 버전에 맞는 것을 pom.xml에 넣어주면 이렇게 생기긔..

 

 

'spring' 카테고리의 다른 글

[스프링] jdbc  (0) 2021.01.11
[스프링] 파일업로드  (0) 2021.01.08
[스프링] MVC - 컨트롤러 구현  (0) 2021.01.08
[스프링] MVC : 패턴  (0) 2021.01.08
[스프링] DI / xml 설정파일 / 어노테이션  (0) 2021.01.06
[스프링] 기본 설정  (0) 2021.01.05
[스프링] 설치  (0) 2021.01.05

[app이름] firstspring이 context경로가 된다.

 

생성 하니까 필요한 라이브러리를 스프링에서 다운시켜주는 중이긔

 

 

 

 

이런 것들을 버전들을 버전에 맞게 수정해주어야 한다.

여기서는 자바만 해주었는데 나중에 스프링도 맞춰줘야함

 

 

 

 

필요한 라이브러리들은 .m2 폴더에 저장되어 있다.

 

 

 

mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.4

 

pom.xml 파일에 필요한 라이브러리를 복사해서 추가해주면 이 라이브러리를 자동으로 또 다운로드 한다.

똑똑하게 필요한 commons-io 까지 알아서 라이브러리 추가해줌!!!

 

 

 

 

 

 

JRE 시스템 라이브러리에서 우클릭 > 빌드패스 > configure웅앵 들어가서 버전에 맞게 설정해준다.

 

 

런타임해서 제대로 뜨면 끗~

 

 

자바 언어로 수정 하면 아래처럼 뜸

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

 

repo.spring.io/release/org/springframework/spring-context/

mvnrepository.com/search?q=spring

mvnrepository.com/search?q=fileupload

spring.io/tools

 

 

1. JDK 설치

2. 이클립스 설치

3. mysql 설치

 

 

방법1 - Spring Tool Suite(STS 설치) > 실행

 

github.com/spring-projects/toolsuite-distribution/wiki/Spring-Tool-Suite-3

방법2 - 이클립스 마켓플레이스에서 설치 

 

.

다시 시작!

 

 

 

spring과 이클립스 둘 다 사용이 가능하다.

 

STS 설정

 

삭제
삭제

 

workspace, spelling, web-css/html/jsp에서 UTF-8로 설정해준다.

+ Recent posts