요청 처리 ( @RequestParam, @RequestHeader, @CookieValue )
웹브라우저 ---------------> Controller
|
|
<------------ hello ( /WEB-INF/views/hello.jsp )
scope 종류에 따라서 저장하고
request.setAttribute(key,value);
session.setAttribute(key,value);
application.setAttribute(key,value)
나중에 jsp에 보여줌
EL: ${key}
1- 의존성 설정
-- pom.xml
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
2- jsp에 taglib 등록
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
@GetMapping("/m1")
public String m1(HttpServletRequest request) {
request.setAttribute("m1", "홍길동");
}
@GetMapping("/m2")
public String m2(Model m) { // 자동으로 new Model()해서 주입됨
m.addAttribute("m1", "홍길동");
m.addAttribute("m1_dto", new LoginDTO("홍길동", "1234"));
}
@GetMapping("/m3")
public String m3(ModelMap m) { // 자동으로 new ModelMap()해서 주입됨.
m.addAttribute("m1", "홍길동");
m.addAttribute("m1_dto", new LoginDTO("홍길동", "1234"));
@GetMapping("/m4")
public String m4(Map<String, Object> m) { // 자동으로 new ModelMap()해서 주입됨.
m.put("m1", "홍길동");
m.put("m1_dto", new LoginDTO("홍길동", "1234"));
@GetMapping("/m5")
public String m5(LoginDTO dto) {
// LoginDTO가 Model이 됨. 즉 내부적으로 request.setAttribute(key, dto);가 됨
// 자동으로 빈 이름으로 key 설정됨
dto.setUserid("이순신");
dto.setPasswd("9876");
return "m5";
}
@GetMapping("/m6")
public String m6(@ModelAttribute("dto_model") LoginDTO dto) {
// LoginDTO가 Model이 됨. 즉 내부적으로 request.setAttribute(명시적 지정, dto);가 됨
// key값 설정은 @ModelAttribute("key값") 사용
dto.setUserid("이순신");
dto.setPasswd("9876");
return "m6";
}
@GetMapping("/m7")
public String m7(@ModelAttribute("list_model") ArrayList<LoginDTO> list) {
// LoginDTO가 Model이 됨. 즉 내부적으로 request.setAttribute(명시적지정, dto);가 됨
// 자동으로 빈 이름으로 key 설정됨
list.add(new LoginDTO("홍길동1", "1234"));
list.add(new LoginDTO("이순신1", "1234"));
return "m7";
}
===> 메서드의 파라미터로 지정해서 Model을 생성함
===> 메서드의 리턴 타입으로 Model을 생성함
View 정보는 요청맵핑값을 view 정보로 사용함
@GetMapping("/m8") // /WEB-INF/views/m8.jsp 찾음
public LoginDTO m8() { // 리턴타입인 LoginDTO가 Model임.
return new LoginDTO("유관순", "1234");
}
@GetMapping("/m9") // /WEB-INF/views/m9.jsp
@ModelAttribute("dto_model")
public LoginDTO m9() { // 리턴타입인 LoginDTO가 Model임.
return new LoginDTO("유관순", "1234");
}
@GetMapping("/m10") // /WEB-INF/views/m10.jsp
@ModelAttribute("list_model")
public ArrayList<LoginDTO> m10() { // 리턴타입인 LoginDTO가 Model임.
ArrayList<LoginDTO> list = new ArrayList<>();
list.add(new LoginDTO("홍길동", "1234"));
list.add(new LoginDTO("이순신", "9876"));
return list;
}
=== > 이전까지는 Model과 View 정보가 분리되서 설정했음
=== > 지금부터는 Model과 View 정보를 한번에 설정 가능
@GetMapping("/m11")
public ModelAndView m11() {
ModelAndView mav = new ModelAndView();
//뷰정보
mav.setViewName("m11"); // /WEB-INF/views/m11.jsp
//모델정보
mav.addObject("m11", "홍길동");
mav.addObject("m11_dto", new LoginDTO("홍길동", "1234"));
List<LoginDTO> list =
Arrays.asList(new LoginDTO("홍길동1", "1234"),
new LoginDTO("홍길동2", "9999"));
mav.addObject("m11_list", list);
return mav;
}
@SessionAttribute(names={"key값","key값"})
Model을 저장할 때 위에서 설정한 key값을 사용하면 session scope에 Model이 저장된다
세션을 사용하고자하는 Controller 마다 매번 @SessionAttribute 설정해야 된다 ⭐
@Autowired
ServletContext ctx;
ctx.setAttribute(key,value);
-- JSP
${requestScope.key}
${sessionScope.key}
${applicationScope.key}
Ajax (jQuery) JSON
웹 브라우저 ----------------------------> Controller (전달된 JSON을 DTO에 자동 저장)
@RequestBody
<----------------------------
전달된 값/DTO 값, DTO
JSON 받을 수 있음
(@ResponseBody)
웹브라우저 @RequestBody 서버
JSON -------------------------> 자바(DTO, List)
<-------------------------
@ResponseBody
<form method="POST" enctype="multipart/form-data" action="fup.cgi">
File to upload: <input type="file" name="upfile"><br/>
Notes about the file: <input type="text" name="note"><br/>
<br/>
<input type="submit" value="Press"> to upload the file!
</form>
반드시 method와 enctype를 다음값으로 설정해야 된다
method="POST"
enctype="multipart/form-data"
멀티 업로드 가능
<input type="file" name="upfile1">
<input type="file" name="upfile2">
public class UploadDTO {
String theText;
MultipartFile theFile;
@PostMapping("/upload")
public String upload(UploadDTO dto) {
String theText = dto.getTheText();
MultipartFile theFile = dto.getTheFile();
long size = theFile.getSize();
String name = theFile.getName();
String fileName = theFile.getOriginalFilename();
String contentType = theFile.getContentType();
logger.info("logger:theText:{}", theText);
logger.info("logger:size:{}", size);
logger.info("logger:name:{}", name);
logger.info("logger:fileName:{}", fileName);
logger.info("logger:contentType:{}", contentType);
// 서버의 물리적인 디렉터리에 파일 저장 예> c:\\upload
// 파일이 저장할 경로만 알려줌
File f = new File("c:\\upload", fileName);
try {
theFile.transferTo(f);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "uploadInfo";
}
// uploadInfo 작업
<h2>uploadInfo</h2>
내용:${uploadDTO.theText}<br>
파일명:${uploadDTO.theFile.originalFilename}<br>
파일명:<a href="down?fileName=${uploadDTO.theFile.originalFilename}">
${uploadDTO.theFile.originalFilename}</a><br>
</body>
//파일다운로드
@Autowired
ServletContext ctx;
@GetMapping("/down")
public void fileDown(HttpServletRequest request, HttpServletResponse response)
throws Exception{
String fileName = request.getParameter( "fileName" );
File fNew = new File("c:\\upload", fileName);
String sFilePath = fNew.getPath();
// String sFilePath = sDownloadPath + fileName;
byte b[] = new byte[4096];
FileInputStream in = new FileInputStream(sFilePath);
String sMimeType = ctx.getMimeType(sFilePath);
System.out.println("sMimeType>>>"+sMimeType );
if(sMimeType == null) sMimeType = "application/octet-stream";
response.setContentType(sMimeType);
String sEncoding = new String(fileName.getBytes("UTF-8"),"8859_1");
response.setHeader("Content-Disposition", "attachment; filename= " + sEncoding);
ServletOutputStream out = response.getOutputStream();
int numRead;
while((numRead = in.read(b, 0, b.length)) != -1) {
out.write(b, 0, numRead);
}
out.flush();
out.close();
in.close();
}
# Controller 호출전에 실행 ( 주요기능 예> 로그인 여부 확인작업등 )
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler)
# Controller 호출후에 실행 ( 주요기능 예> View 변경 및 Model 추가/수정 )
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView mav) throws Exception
# JSP가 웹브라우저에 랜더링 된후 실행
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
MyHandlerInterceptor myHandlerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myHandlerInterceptor)
.addPathPatterns("/login","/logout");
}
==================================
cf) 필터(filter)
서블릿, Spring framework에서 가로채기
(서블릿 요청전)
웹브라우저 ------필터1--필터2------> 서블릿
<----- 필터1--필터2------
(웹브라우저 응답전)
기능: 서블릿 요청전 또는 웹브라우저 응답전에 특정 기능을 추가/변경/삭제할 수 있다.
예>
post요청
웹브라우저 -------------------> 서블릿1 post한글처리. request.setCharacterEncoding("utf-8");
post요청
-------------------> 서블릿.. post한글처리. request.setCharacterEncoding("utf-8");
post요청
-------------------> 서블릿n post한글처리. request.setCharacterEncoding("utf-8");
웹브라우저 -------------------> 서블릿1
post요청
---------필터-------> 서블릿..
post요청
-------------------> 서블릿n
@GetMapping("/errorPage")
public String errorPage() {
logger.info("logger:MainController:{}", "/errorPage 요청");
throw new IllegalArgumentException("IllegalArgumentException 발생됨");
}
@ExceptionHandler
# Controller 안에서
@ExceptionHandler(value = {NullPointerException.class,
IllegalArgumentException.class})
public String errorPage(Exception e, Model m) {
logger.info("logger:errorPage:{}", e.getMessage());
m.addAttribute("error_message", e.getMessage());
return "errorPage"; // errorPage.jsp
}
@ControlAdvice
# 새로운 빈에서
@ControllerAdvice
public class GlobalExceptionHandler {
Logger logger = LoggerFactory.getLogger(getClass());
@ExceptionHandler(value = {ClassCastException.class,
ArithmeticException.class})
public String errorPage(Exception e, Model m) {
logger.info("logger:errorPage:{}", e.getMessage());
m.addAttribute("error_message", e.getMessage());
return "errorPage"; // errorPage.jsp
}
}
https://docs.spring.io/spring-boot/docs/2.7.18/reference/htmlsingle/#features.internationalization
가. AcceptHeaderLocaleResolver
- 요청 헤더값을 이용해서 locale 정보를 얻음
- Accept-Language 헤더값 이용
- 기본적으로 적용되는 방법임.
나. CookieLocaleResolver
- 쿠키를 이용해서 locale 정보를 저장및얻음
- setLocale("ko|en|");
다. SessionLocaleResolver
- 세션을 이용해서 locale 정보를 저장및얻음
- setLocale("ko|en|");
구현 1
1) 리소스 번들 파일 작성 (resouece bundle 파일)
- 문법:
src/main/resources 폴더
파일명-언어코드.properties
- 키=값
- 기본 번들 파일: message.properties
greeting=안녕하세요
한국어 번들 파일: message_ko.properties
greeting=안녕하세요
영어 번들 파일 : message_en.propertis
greeting=hello
- 번들 파일의 인코딩은 모두 utf-8로 변경.
2) application.properties에 리소스 번들 등록
# 리소스 번들 파일 등록
spring.messages.basename=bundle/message
spring.messages.encoding=utf-8
3) spring.messages.fallback-to-system-locale=false
기본: true. message.properties 가 아닌 system의 locale(제어판의 국가별 설정)ㅑ 적용함.
false. message.properties 적용.
4) SessionLocaleResolver 생성
@ Configuration
public class WebMvc {
// 기본인 AcceptHeaderLocaleResolver 인데
// 기본을 SessionLocaleResolver로 변경하는 작업이다.
@Bean
public SessionLocaleResolver localeResolver() {
SessionLocaleResolver locale =
new SessionLocaleResolver();
locale.setDefaultLocale(new Locale("ko"));
return locale;
}
}
5) Controller 에서 개발자가 직접 locale 변경
@GetMapping("/bundle")
public String bundle( HttpServletRequest request,
HttpServletResponse response,
@RequestParam String lang) {
//SessionLocaleResolver의 로케일을 변경.
locale.setLocale(request, response,
new Locale(lang));
@Configuration
public class WebMvc implements WebMvcConfigurer{
// 기본인 AcceptHeaderLocaleResolver 인데
// 기본을 SessionLocaleResolver로 변경하는 작업이다.
@Bean
public SessionLocaleResolver localeResolver() {
SessionLocaleResolver locale =
new SessionLocaleResolver();
locale.setDefaultLocale(new Locale("ko"));
return locale;
}
//LocalChangeInterceptor 생성
@Bean
public LocaleChangeInterceptor changeInterceptor() {
LocaleChangeInterceptor xxx = new LocaleChangeInterceptor();
// ?lang=en|ko|jp
xxx.setParamName("lang");
return xxx;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(changeInterceptor());
}
}
/META-INF/resources/webjars/jquery/3.7.1/jquery.min.js
< script src="webjars/jquery/3.7.1/jquery.min.js"></ script>
/META-INF/resources/webjars/bootstrap/5.3.3/css/bootstrap.min.css
/META-INF/resources/webjars/bootstrap/5.3.3/js/bootstrap.min.js
< script src="webjars/bootstrap/5.3.3/js/bootstrap.min.js"></ script>
< link rel="stylesheet" href="webjars/bootstrap/5.3.3/css/bootstrap.min.css">
<!-- https://mvnrepository.com/artifact/org.webjars/jquery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.7.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/bootstrap -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
: 유효성 체크하기 위한 DTO
(Command Bean / form backing object : 양식보조객체 라고도 함)
==> 변수에 어노테이션으로 유효성 조건을 지정한다
public class memberDTO {
@NotNull
String userid;
@Size(min=3, message="세 글자 이상입니다!!")
String username;
// 010-1234-5678 전화번호 정규표현식 검색해서 쓰세용
//@Pattern()
//String phone;
@NotNull
@FutureOrPresent(message = "현재 또는 미래 날짜만 가능합니다")
LocalDate targetDate;
화면 요청 (GET)
Controller -----------------------> jsp
<-----------------------
실제 요청 (POST)
화면요청(GET)
Controller ---------------------> jsp
<---------------------
실제요청(POST)
@GetMapping("/member") // 화면 요청
public String memberForm(ModelMap m) {
MemberDTO dto = new MemberDTO();
// MemberDTO dto = new MemberDTO("aaa","홍길동", LocalDate.now());
// m.addAttribute("memX", dto); // 임의의 값 지정하면 에러 발생
m.addAttribute("memberDTO", dto); // command bean으로 반드시 설정한다
return "memberForm";
}
@PostMapping("/member") // 로직 요청
public String member(@Valid MemberDTO dto, BindingResult result) {
System.out.println("MemberDTO" + dto);
if(result.hasErrors()) {
return "memberForm";
}
return "memberInfo";
}
<%@ taglib uri="http://www.springframework.org/tags/form"
prefix="form"%>
<form:form method="post"
modelAttribute="memberDTO">
아이디:<form:input type="text" path="userid" />
<form:errors path="userid"></form:errors>
<br>
이름:<form:input type="text" path="username" />
<form:errors path="username"></form:errors>
<br>
날짜:<form:input type="date" path="targetDate" />
<form:errors path="targetDate"></form:errors>
<br>
<input type="submit" value="가입">
</form:form>