<select id="login"  parameterType="user" resultType="user" >
		SELECT * FROM user_info
		WHERE UI_ID = #{uiId}
		AND UI_PW = #{uiPw}
		
	</select>
view
로그인 성공, 실패 모두 로그인 화면으로 들어온다. 메시지에 따라 이동
$(document).ready(function(){
  var loginMsg="${loginMsg}";
  if(loginMsg!=""){
    alert(loginMsg);
    if(loginMsg=="로그인 성공!"){ 
      // 로그인 성공을 보여주고나서 이동
      location.href="${path}/prjList.do"; 
    }
  }
});
메서드 매개변수: HttpSession session, 유저 객체
유저 인스턴스 = service.login(유저 객체)
session.setAttribute("유저", 유저 인스턴스)Controller 어노테이션: @SessionAttributes("유저객체")
// vo객체 이름이랑 앞글자가 소문자인거 말곤 같아야한다
Controller 내부
	@ModelAttribute("user_info")
	public USER_INFO getUser() {
		return new USER_INFO();
	}
메서드 매개변수 : @ModelAttribute("유저객체") 유저객체 sch, Model d
d.addAttribute("user_info",sch);checkbox이기에 boolean형태로 controller에 넘어간다.
Controller
느낀점: 음... controller 이렇게 지저분하게 코드를 짜도 괜찮을까..? Service 쪽에 넘길 걸...
				// 아이디 기억
         if(saveId) {
              // 쿠키 생성해서 아이디속성에 저장 
                  // => 사용하려면 EL태그 cookie.id.value로 사용하라
              Cookie cookie = new Cookie("id", sch.getUiId()); 
              //	응답에 저장해서 보내
              response.addCookie(cookie);
          } else {
              Cookie cookie = new Cookie("id", sch.getUiId()); 
              // 쿠키를 삭제
              cookie.setMaxAge(0); 
              response.addCookie(cookie);
          }
			```
view
        아이디: <input value="${cookie.id.value}> 
        아이디기억 창: <input type="checkbox" name="saveId" id="checkbox-signin">
			function loginchk(){
				if($("[name=uiId]").val().trim()==""){
					alert("아이디를 입력해주세요.");
					// 값이 들어가있지 않으면 false로 리턴 
					$("[name=uiId]").focus();
					return false;
				}else if ($("[name=uiPw]").val().trim()==""){
					alert("비밀번호를 입력해주세요.");
					$("[name=uiPw]").focus();
					return false;
				}else{
					return true;
					// 유효성 검증 후 값이 전부 들어가 있으면 main으로 이동 
				}
			}
      메서드 매개변수: HttpSession session
      session.invalidate(); // 세션 종료
      메서드 매개변수: SessionStatus sessionStatus
      sessionStatus.setComplete(); // 
아마 setComplete()로 충분할 수 있지만 혹시 모르니 session 종료하는게 나을 수도?
// 세션 종료
		session.invalidate(); 
		// @SessionAttritbute를 사용하게되면 session에도 값을 담게 된다. 
		// 그래서 session.getAttribute가능
			// but session.invalidate()를 통해 세션 종료해도 계속 값이 남는다. 
			// 아마 스프링 컨테이너에 계속 있는듯? 
			// 세션 만료 후에는 세션에서 가져올 때(getAttributes)는 안되지만,
			// 이렇게 @ModelAttribute로 가져오는건 그대로 유지가 되네
	
		
		s.setComplete();
	<session-config> 
<!-- jsp는 보통 was 서버인 tomcat으로 실행되는 경우가 많기에 
		tomcat의 session time 받아서 -->
		<session-timeout>30</session-timeout> 
	</session-config>// 로그인할 때만 들어올 수 있도록 // 참조: https://erim1005.tistory.com/28
			
			<c:if test="${empty user_info.uiName}">
			
				let url = '${requestScope['javax.servlet.forward.servlet_path']}'; // 컨트롤러 url주소
				let queryString = '${requestScope['javax.servlet.forward.query_string']}'; //queryString 
				url += (queryString != '')? '?'+queryString: '';
		
				// JSP 현재 url 정보 얻기 => ${pageContext.request.requestURL}는 실제 jsp 물리적 경로...
				
				alert("로그인 후, 이용해주세요."); 
				
				location.href="${path}/loginFrm.do?toURL="+url;
			</c:if><input name="toURL" value="${toURL}" hidden />if(toURL.equals("")) { 
	// main에서 로그인할 때는, header 쪽에서 주는 toURL이 없으니
				return "main_login//login.jsp";
			}
			
			return "redirect:"+toURL;프로세스
localeResolver.setLocale(request, response, locale); 해주면 된다.dispatcherservlet
localeResolver는 4가지가 있는 데, 그 중 SessionLocaleResolver 사용
<bean id="messageSource"
		class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basenames">
			<list>
				<value>message.msg</value>
			</list>
		</property>	
	</bean>
	<bean id="localeResolver" 
	class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
locale이라는 클래스 객체를 통해 언어 매개변수(lang)로 생성자 만든다.
스프링 MVC는 LocaleResolver를 이용해서 웹 요청과 관련된 Locale을 추출하고,
이 Locale 객체를 이용해서 알맞은 언어의 메시지를 선택
localeResolver는 언어를 선택하는 방법이 여러가지 있으나 여기서는 session을 활용하였다.
package springweb.a02_mvc.a01_controller;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.LocaleResolver;
@Controller
public class MultiLangCtrl {
	// 컨테이너에 선언된 언어선택 객체..
	@Autowired(required=false)
	private LocaleResolver localeResolver;
	
	// 1. 초기화면 호출.
	@GetMapping("multi.do")
	public String multi() {
		return "WEB-INF\\multiLanguage.jsp";
	}
	// 2. 언어 선택에 따른 변환처리.
	@GetMapping("choiceLan.do")
	public String choide(@RequestParam("lang") String lang,
			HttpServletRequest request,
			HttpServletResponse response) {
		System.out.println("선택한 언어:"+lang);
		Locale locale = new Locale(lang);
		localeResolver.setLocale(request, response, locale);
		
		return "WEB-INF\\multiLanguage.jsp";
	}
	
}
- spring tag lib 호출 선언
	<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>	
$(document).ready(function(){
		<%-- 
		
		# select 옵션에 의해서 
		선택되었을 때, 언어의 변경 처리하는 controller 호출 및 처리된 결과 확인..
		
		만약 값이 바뀌었을 떄 빈 값이 아니라면 해당 언어로 변경
		--%>
		$("#selectLan").val("${param.lang}")
		$("#selectLan").change(function(){
			if($(this).val()!=""){
				location.href="${path}/choiceLan.do?lang="+$(this).val();
			}
		});
	
	});
html 텍스트는 글자 대신 <spring:message code="id"/> 같이이름과 이메일 주소를 가지고 아이디 찾기 진행
AJAX를 활용하여 컨트롤러에서 해당하는 아이디가 있는지 여부에 따라
// 확인용
function findId(){
      $.ajax({
      url : "${path}/getUserId.do",
      type : "get",
      dataType : "json",
      data : $("form").serialize(),
      success : function(data){
      	userId = data.userId;
          if(userId != null){
              alert("귀하의 아이디는 "+userId+"입니다.");
    
          }else{
              alert("정보가 올바르지 않습니다.");
          }
      }
})
			}
이름과 아이디를 통해 비밀번호 찾기 진행
비밀번호 찾기가 진행되면 해당하는 아이디의 비밀번호를 임시비밀번호로 변경
해당하는 정보가 있다면 가입했을 때 작성한 이메일 주소로 임시비밀번호 전송
프로필 수정해서 비밀번호를 바꾸도록 하는 방식
// 확인용
function findPw(){
	
        $.ajax({
        url : "${path}/getUserPw.do",
        type : "get",
        dataType : "json",
        data : $("form").serialize(),
        success : function(data){
        		userPw = data.userPw;
              if(userPw != null){
                  alert("임시 비밀번호를 이메일로 보냈습니다.");
        
              }else{
                  alert("정보가 올바르지 않습니다.");
              }
          }
})
}
Controller
@RequestMapping("/getUserPw.do")
	public String getUserPw(USER_INFO user, Mail email, Model d) {
		
		String pw = service.getPw(user);
		
		if(pw==null) {
			
			return "pageJsonReport";
		}
		// 랜덤 비밀번호로 변경
		service.updateTempPw(email, user);
		// 메시지용
		d.addAttribute("userPw", 1);
	
		return "pageJsonReport";
	}
Service
// 메일 발송 메서드 
public void sendMail(Mail email, String receiever, String tempPw) {
		
		// 멀티미디어형 메일 데이터 전송.
		MimeMessage mmsg = sender.createMimeMessage();
	
		try {
			// 제목 설정
			email.setTitle("BORAM3 PMS 임시비밀번호입니다.");
			mmsg.setSubject(email.getTitle());
			
			// 내용 설정
			String content = "임시비밀번호를 전송합니다. 로그인 후, "
					+ "비밀번호 수정을 진행해주세요. <br>"
					+ "임시비밀번호: <span style='font-weight: 700'>"
					+tempPw +"</span>"
					+ "<br><br> BORAM3 PMS로 "
					+ "<a href='http://14.33.134.85:7090/borampms/main.do'>이동</a>";
			
			email.setContent(content);
			// html 태그를 넣어주기 위해
			mmsg.setContent(email.getContent(), "text/html;charset=euc-kr");
						
			// 수신자 설정
			email.setReciever(receiever);
			mmsg.setRecipient(RecipientType.TO, new InternetAddress(email.getReciever()));
			
			// 발송 처리.
			sender.send(mmsg);
			
		} catch (MessagingException e) {
			System.out.println("메일 발송 에러:"+e.getMessage());
		} catch (Exception e) {
			System.out.println("일반 에러 발생:"+e.getMessage());
		}
	
	}
// 임시비밀번호로 변경 후, 메일 발송 시작
public void updateTempPw(Mail email, USER_INFO user) {
		
		String tempPw = "";
		int idx = 0;
		char[] charList = new char[] {
				'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
				'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
		for (int i = 0; i < 8; i++) {
			idx = (int)(Math.random() * 26);
			tempPw += charList[idx];
		}
		
		// 새 비밀번호로 설정
		user.setUiPw(tempPw);
		
		// 이메일 주소 가져오기
		String receiver = dao.getEmail(user);
		
		// 메일 발송
		sendMail(email, receiver, tempPw);
		dao.updateTempPw(user);
	};
계정의 비밀번호 앞에는 {noop}이 기본 세팅된다.
<sec:authentication-manager>
	
		<!-- 
		문자열로 권한 접근.. -->
		<sec:authentication-provider>
			<sec:user-service>
				<sec:user name="himan" password="7777" 
				          authorities="ROLE_USER" />
				<sec:user name="manager" password="qwer" 
				          authorities="ROLE_MANAGER" />
				<sec:user name="admin" password="asdf" 
				          authorities="ROLE_ADMIN,ROLE_USER" />
			</sec:user-service>
		</sec:authentication-provider>
		
		<!--DB로 처리시 --> 
		<sec:authentication-provider ref="customAuthenticationProvider" />
		<sec:authentication-provider
			user-service-ref="customUserDetailsService" />
		<sec:authentication-provider>
			<sec:jdbc-user-service data-source-ref="dataSource"
				id="jdbcUserService" />
			
			<sec:password-encoder ref="passwordEncoder" />
			
		</sec:authentication-provider>		
	</sec:authentication-manager>
<mvc:view-controller path="/index" view-name="/view/index.jsp" />
	
	<mvc:view-controller path="/admin/" view-name="/manager/managerUser.jsp" />	
	<mvc:view-controller path="/adminLoginform" view-name="/main_login/adminLogin.jsp" />
	<mvc:view-controller path="/security/accessDenied" view-name="/view/security/accessDenied.jsp" />