흐음... 파일 업로드가 필요한경우 html 폼의 enctype 속성을 "multipart/form-date" 로 설정해야한다.

스프링은 Multipart지원 기능을 제공하고 있기 때문에 쉽게 처리 가능하다고 하네?

우선 언제나 그렇듯이.. 뭔가를 등록해야한다. .. 쓸려면 말야~
뭐겠니?? 빈이지.

MultipartResolver 를 등록해줘야 한다. 해당 빈은 Multipart 형식으로 데이터가 전송된 경우, 해당 데이터를 스프링 MVC 에서 사용할 수 있도록 변환해준다.
예로, @PathVariable 어노테이션을 이용해서 Multipart로 전송된 파라미터와 파일을 사용할 수 있도록 해준다.

스프링이 제공하는 기본 MultupartResolver는 CommonsMultipartResolver 이다.
해당 리졸버는 Commons FileUpload API를 이용해서 Multipart를 처리해준다. 

<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>

CommonsMultipartResolver 가 제공하는 프로퍼티는..... 찾아보면 나옴; (뭐.. 최대업로드 사이즈, 최대 메모리 사이즈, 인코딩 타입등을 설정할 수 있다)

1. 업로드한 파일을 전달받는 방법

1.1 @RequestParam 어노테이션을 이용한 업로드된 파일 접근

<h3>@RequestParam 사용</h3>
<form action="submitReport1.do" method="post" enctype="multipart/form-data">
학번: <input type="text" name="studentNumber" />
<br/>
리포트파일: <input type="file" name="report" />
<br/>
<input type="submit" />
</form>

파라미터 이름은 report 이고 @RequestParam어노테이션과 MultipartFile 타입의 파라미터를 이용해서 파일 데이터를 전달받는다.


@RequestMapping(value = "/report/submitReport1.do", method = RequestMethod.POST)
public String submitReport1(@RequestParam("studentNumber") String studentNumber, @RequestParam("report") MultipartFile report) {
printInfo(studentNumber, report);
return "report/submissionComplete";
}
MultipartFile을 통해서 파일 이름, 데이터, 크기등을 알 수 있다.

1.2 MultipartHttpServletRequest를 이용한 업로드된 파일 접근


@RequestMapping(value = "/report/submitReport2.do", method = RequestMethod.POST)
public String submitReport2(MultipartHttpServletRequest request) {
String studentNumber = request.getParameter("studentNumber");
MultipartFile report = request.getFile("report");
printInfo(studentNumber, report);
return "report/submissionComplete";
}
MultipartHttpServletRequest 인터페이스는 스프링이 제공하는 인터페이스로서 Multipart 요청이 들어올 때 내부적으로 원본 HttpServletRequest 대신 사용된다.

MultipartHttpServletRequest 는 어떠한 메소드도 선언하고 있지 않고 단지, MultipartRequest 와 HttpServletRequest 를 상속받고 있다.


1.3 커맨드 객체를 이용한 업로드된 파일접근
흐음.. 우리가 파라미터로 받는 커맨드 객체를 통해서도 .. 되겠지

해당 커맨드 클래스에 파라미터와 동일한 이름의 MultipartFile 타입 프로퍼티를 추가해주기만 하면된다.

public class ReportCommand {
....
public void setReport(MultipartFile report) {
this.report = report;
}
 }

public MultipartFile getReport() {
return report;
}
 
업로드 파일의 파라미터 이름이 report 인 경우 위와 같이 report 관련 프로퍼티를 커맨드 클래스에 추가한다.

위처럼 MultuFile 타입의 프로퍼티를 커맨드 클래스(ReportCommand)에 추가했다면 @RequestMapping 메서도의 커맨드 객체로 이용할 수 있다.
        @RequestMapping(value = "/report/submitReport3.do", method = RequestMethod.POST)
public String submitReport3(ReportCommand reportCommand) {
printInfo(reportCommand.getStudentNumber(), reportCommand.getReport());
return "report/submissionComplete";
}











 



 












 

'IT > 스프링' 카테고리의 다른 글

캐시옵션 설정  (0) 2012.01.19
HandlerInterceptor  (0) 2012.01.19
Validator / Error interface .... in Spring  (0) 2012.01.16
Ant 경로 패턴 in @RequestMapping  (0) 2012.01.16
PathVariable 어노테이션을 이용한 URI 템플릿...  (0) 2012.01.16
이걸 제대로 쓰면 좋은데 말이지...

둘다 인터페이스이다.

컨트롤러에서 커맨드 객체 (간단하게는 form 값을 넘겨받은 클래스를 의미 ) 를 생성한뒤에 Validator 에 넘겨서 검증요청한다.

 인터페이스에는 2가지 메소드가 있는데

ㄱ. boolean supports(Class <?> clazz)
: 해당 클래스에 대한 값 검증을 지원하는 지의 여부를 리턴한다.
ㄴ. void validate (Object target, Errors errors)
: target 객체에 대한 검증을 실행한다. 검증결과 문제가 있을 경우 errors 객체에 어떤 문제인지에 대한 정보를 저장한다.
즉, 리턴은 없고 errors에 담겨온다.


if (memberInfo.getId() == null || memberInfo.getId().trim().isEmpty()) {
errors.rejectValue("id", "required");
}

rejectValue 메소드는 "id" 프로퍼티값이 잘못됐고, 에러코드로 "required"를 남겼다.

Validator 클래스를 작성하면, 다음으로 컨트롤러 클래스에서 Validator를 이용해서 커맨드 객체를 검증하는 것이다. 

검증하는 코드를 추가하는 작업은

ㄱ. @RequestMapping 어노테이션 메소드에서 커맨드 객체 다음 파라미터로 BindingResult 타입이나 , Errors 타입의 파라미터를 추가한다.
ㄴ. 메소드내에 Validator 객체를 생성한뒤 validate() 메소드에서 커맨드객체와 BindingResult 또는 Errors 타입 파라미터를 전달한다.
ㄷ. Errors.hasErrors() 메소드를 이용해서 에러가 존재하는지 확인하고, 에러가 존재할 경우 알맞은 처리를 한다.

사용은 아래와 같이...
@RequestMapping(method = RequestMethod.POST)
public String submit(@ModelAttribute("command") MemberInfo memberInfo,BindingResult result) {
new MemberInfoValidator().validate(memberInfo, result);
if (result.hasErrors()) {
return "account/creationForm";
}
return "account/created";
}


2. Errors / BindingResult 인터페이스
Errors 와 BindingResult 인터페이스의 사용처를 보면,
ㄱ. Errors : 유효성 검증 결과를 저장할때 사용
ㄴ. BindingResult : Errors 인터페이스의 하위 인터페이스로 폼 값을 커맨드객체에 바인딩한 결과로 저장함.

2.1 Errors
값이 올바르지 않을경우 reject() 또는 rejectValue()메소드를 이용해서 어떤 필드가 잘못되었는지, 관련된 에러가 무엇인지 입력받는다.

reject() 메소드는 검증 대상 객체의 전체적인 에러를 설정. (이게 글로벌..을 의미함)
rejectValue() 메소드는 특정 프로퍼티의 검증에러를 설정한다.

책에서 찾아봐라 -ㅅ- 귀찮다


        @RequestMapping(method = RequestMethod.POST)
public String submit(@Valid LoginCommand loginCommand, 
BindingResult result) {
if (result.hasErrors()) {
return formViewName;
}
try {
authenticator.authenticate(loginCommand);
return "redirect:/index.jsp";
} catch (AuthenticationException e) {
// 이 경우의 익셉션은 로그인 실패이지 값이 없거나 하는게 아니다. 즉 깂이 잘못된(아이디나 패스워드가 잘못된) 객체의 문제이다.
//  그러면 아래체럼... reject를 이용해 글로벌에러정보(전체적인 에러정보) 를 추가할 수 있다 
result.reject("invalidIdOrPassword", new Object[] { loginCommand.getUserId() }, null);
return formViewName;
}
}

rejectValue 를 이용하면 객체의 개별 프로퍼티(필드)에 대한 에러정보를 추가할 수 있다.

@Override
public void validate(Object target, Errors errors) {
MemberInfo memberInfo = (MemberInfo) target;
if (memberInfo.getId() == null || memberInfo.getId().trim().isEmpty()) {
errors.rejectValue("id", "required");
}
if (memberInfo.getName() == null
|| memberInfo.getName().trim().isEmpty()) {
errors.rejectValue("name", "required");
}
        ....
        }

rejectValue 는 맵과 달리 계속 추가적으로 에러를 등록할 수 있다. (같은 키값에 말야)
그러면 그 만큼 나중에 확인가능하다. (카운트가 가능한게 이 이유임)

에러가 발견됐다면 페이지 이동시켜버리면된다. 

@RequestMapping(method = RequestMethod.POST)

public String submit(@ModelAttribute("command") MemberInfo memberInfo,

BindingResult result) {

new MemberInfoValidator().validate(memberInfo, result);

if (result.hasErrors()) {

return "account/creationForm";

}

return "account/created";

}



보다시피 return 이 String 이고 주소를 줘서 웹이동을 하게 되는 것임.

BindingResult 인터페이스의 기본 구현클래스(AbstractBindingResult) 클래스는 MessageCodesResolver를 사용하여 에러코드에 대한 에러메시지를 추출한다. 기본적으로 DefaultMessageCodeResolver클래스를 MessageCodesResolver로 사용한다네..

DefaultMessageCodeResolver 를 이용해서 자동으로 에러메시지를 생성하려면 MessageSource를 빈 객체로 등록해야한단다.

에러메시지를 출력할 때에는 스프링이 제공하는 <form:errors> 커스텀 태그를 사용하면된다.

뷰로 jsp를 사용할 경우 2가지 방식으로 에러메시지를 설정한다.
ㄱ. <spring:hashBindErrors> 커스텀 태그를 이용하여 에러정보를 설정
ㄴ, <form:form> 태그를 이용하여 에러정보를 설정

아... 귀찮다 예제는 그냥 책봐라...


ValidationUtils
뭐.. null 이냐 그냥 값없음(whitespace) 이냐를 판단하는 유틸을 제공하더라.
ValidationUtils 이며 메소드로 StringUtils와의 차이는 단순 결과리턴이 아닌 reject등의 데이터가 저장되는거랄까? 즉 rejectValue 등을 호출할 필요가 없다 그거지...

ValidationUtils.rejectEmptyOrWhitespace(errors,"id","required");

위처럼 처리가능하다. ... 나머지는 찾아봐라.. 많다 -ㅅ-;

@Valid 어노테이션 ,  @InitBinder 어노테이션을 이용한 검증

위에서는 Validator 객체를 생성하고 validate를 호출해서 검사했지만 어노테이션으로도 처리 가능하다.

즉... 어노테이션 달고 그냥 자동으로 되는거라 그거지.

@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new LoginCommandValidator());
}

어떤 Validator가 커맨드 객체를 검증할지 여부를 위처럼 설정한다.

그리고 validate() 호출하지 않고 그냥 BindingResult 를 보고 판단한다.
        @RequestMapping(method = RequestMethod.POST)
public String submit(@Valid LoginCommand loginCommand, BindingResult result) {
if (result.hasErrors()) {
return formViewName;
}
try {
authenticator.authenticate(loginCommand);
return "redirect:/index.jsp";
} catch (AuthenticationException e) {
result.reject("invalidIdOrPassword", new Object[] { loginCommand
.getUserId() }, null);
return formViewName;
}
}

만일 @Valid 가 적용된 뒤에 BindingResult 나 Errors 타입이 없다는 의미는... 에러시의 처리를 하지 않겠다는 의미가 된다. (500에러가 나올것임)












 



 




'IT > 스프링' 카테고리의 다른 글

HandlerInterceptor  (0) 2012.01.19
파일 업로드 in spring... 3  (1) 2012.01.18
Ant 경로 패턴 in @RequestMapping  (0) 2012.01.16
PathVariable 어노테이션을 이용한 URI 템플릿...  (0) 2012.01.16
URI 매칭.. (서블릿 맵핑)  (0) 2012.01.13
 
참고로 @RequestMapping 어노테이션은 Ant 스타일의 패턴을 지원한다.
? : 1개의 문자와 매칭
* : 0개이상의 문자와 매칭
** : 0개 이상의 디렉토리와 매칭

기억하도록~~

'IT > 스프링' 카테고리의 다른 글

파일 업로드 in spring... 3  (1) 2012.01.18
Validator / Error interface .... in Spring  (0) 2012.01.16
PathVariable 어노테이션을 이용한 URI 템플릿...  (0) 2012.01.16
URI 매칭.. (서블릿 맵핑)  (0) 2012.01.13
@ModelAttribute  (2) 2012.01.13



흐음.. RESTful 서비스의 URI 형태가 이런거였구나.

즉.xxxx/xxxx/info?user=id  형태의 url이 있다면
-->
xxxx/xxxx/info/user/id .. 뭐 이런것 처럼 파라미터가 uri에 포함되도록 하는 형태란다.

이걸 스프링3 에서 흉내?? 낼수 있는데 URI 템플릿 기능이란다.

1. 설정방법
방법은
@RequestMapping 어노테이션값으로 { 템플릿변수 } 를 사용한다. 
@PathVariable 어노테이션을 이용해서 { 템플릿 변수 } 와 동일한 이름을 갖는 파라미터를 추가한다. 

@Controller
public class CharacterInfoController {
    @RequestMapping( "/game/users/{userId}/characters/{characterId}" )
    public String characterInfo(@PathVariable String userId, @PathVariable int characterId,ModelMap model) {
        model.addAttribute("userId",userId);
        model.addAttribute("characterId",characterId);
        ....
    }

RequestMapping 어노테이션에 변수를 포함하고 있다.
이들변수는 @PathVariable 어노테이션이 적용된 동일한 이름을 갖는 파라미터에 매칭된다. 



/game/users/ezsnotes/characters/sorcerer

하면 userId / characterId에 ezsnotes , sorcerer 가 들어간다.

만약 @PathVariable 어노테이션에 값을 주면 변수이름을 동일하게 하지 않고 지정할 수 있게 된다.


2. 추가 설정방법
 @Controller

@RequestMapping("/game/users/{userId}")
public class CharacterInfoController {

@RequestMapping("/characters/{characterId}")
public String characterInfo(@PathVariable String userId,
@PathVariable int characterId, ModelMap model) {
model.addAttribute("userId", userId);
model.addAttribute("characterId", characterId);
return "game/character/info";
}
}

위의 코드처럼 클래스와 메소드에 각각 RequestMapping을 걸어놓게 되면?
메소드에 적용한 @RequestMapping 어노테이션의 값은 클래스에 적용한 @RequestMapping 어노테이션의 값을 기본경로로 쓰게 된다.


메소드에 적용된 어노테이션의 값은 /characters/{characterId} 인데 실제 매칭되는 값은 클래스에 적용된 어노테이션의 값을 포함한
/game/users/{userId}/characters/{characterId} 가 된다.






















'IT > 스프링' 카테고리의 다른 글

Validator / Error interface .... in Spring  (0) 2012.01.16
Ant 경로 패턴 in @RequestMapping  (0) 2012.01.16
URI 매칭.. (서블릿 맵핑)  (0) 2012.01.13
@ModelAttribute  (2) 2012.01.13
모델 생성.... (Model )  (0) 2012.01.13


DispatcherServlet은 DefaultAnnotationHandlerMapping 클래스를 기본 HandlerMapping 구현체로 사용한다.

 @RequestMapping 의 주의사항..

@RequestMapping("/search/game.do")
public String search(...) {
...


@RequestMapping("/game/info")
public String info(...) {
...


코드를 보면 /search/game.do 는 search에서 처리하고, /game/info 는 info에서 처리할듯 하지만...
첫번째것은 맞고 두번째는 틀렸다.

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
<url-pattern>/game/*</url-pattern>
</servlet-mapping>

url-pattern 에서 /game/* 로 설정했기 때문이라네?
url-pattern값으로 디렉토리를 포함한 패턴을 지정하게 되면 서블릿 경로는 /game 이 되며, 
서블릿 경로를 제외한 나머지 경로를 이용해서 @RequestMapping 어노테이션의 값과 매칭여부를 판단한단다.

해서 game/info 의 요청이 오면 실제 요청 URI 는 /info가 된다. 
허나 RequestMapping 에는 /game/info라고 했으므로 /info와 맞지 않게 된다.


이런 이유는 DispatcherServlet 이 기본적으로 사용하는 HandlerMapping 구현체와 HandlerAdapter 구현체가 전체 경로를 사용하지 않도록 설정되어있기 때문이란다.

해서 사용하게 설정하면... 위의 경우 잘 되겠지?
즉, 서블릿 경로를 포함한 전체 경로를 이용해서 매칭 여부를 판단하도록 설정하려면, 
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" p:alaywaUseFullPath="true"/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerAdapter" p:alwaysUseFullPath ="true"/>
 


 










 



'IT > 스프링' 카테고리의 다른 글

Ant 경로 패턴 in @RequestMapping  (0) 2012.01.16
PathVariable 어노테이션을 이용한 URI 템플릿...  (0) 2012.01.16
@ModelAttribute  (2) 2012.01.13
모델 생성.... (Model )  (0) 2012.01.13
@Controller 어노테이션... - 1 -  (0) 2012.01.10


@ModelAttribute 를 이용하면 2가지 작업이 가능

ㄱ. @RequestMapping 어노테이션이 적용되지 않은 별도 메소드로 모델에 추가될 객체를 생성가능
ㄴ. 커맨드 객체의 초기화 작업을 수행

두개의 RequestMapping 된 메소드가 같은 내용의 모델을 필요로 한다고 할때, 보통 그냥 별도의 메소드로 빼서 그것을 참조하게
한다. 

단 이렇게 하면 공통 메소드에 추가 조건절이 들어갈 수 도 있고 리턴에 대해서도 사용하는 측에서 맞춰야한다.

이때 @ModelAttribute를 사용할 수 있다.

 @ModelAttribute 를 메소드에 적용하면 해당 메소드가 생성한 객체가 뷰에 전달된다!!!!


아하.. 그래서 return 에 없는 객체들을 jsp 에서 참조가능했구나!!!!!!

즉 이 어노테이션은 ModelAttribute , 모델속성!! 이라는 의미의 단어를 그대로 뜻하는 것이다!!! 


@Controller
public class GameSearchController {
@Autowired
private SearchService searchService;

@ModelAttribute("searchTypeList")
public List<SearchType> referenceSearchTypeList() {
List<SearchType> options = new ArrayList<SearchType>();
options.add(new SearchType(1, "전체"));
options.add(new SearchType(2, "아이템"));
options.add(new SearchType(3, "캐릭터"));
return options;
}

@ModelAttribute("popularQueryList")
public String[] getPopularQueryList() {
return new String[] { "게임", "창천2", "위메이드" };
}

@RequestMapping("/search/main.do")
public String main() {
return "search/main";
}

@RequestMapping("/search/game.do")
public ModelAndView search(@ModelAttribute("command") SearchCommand command) {
ModelAndView mav = new ModelAndView("search/game");
System.out.println("검색어 = " + command.getQuery().toUpperCase());
SearchResult result = searchService.search(command);
mav.addObject("searchResult", result);
return mav;
}


해서 위의 콘트롤러를 보면 리턴해줄 모델의 값은 단지 mav일뿐이다. 허나 @ModelAttribute 어노테이션을 다른 메소드에 붙이므로써
모델에 속성을 추가하게 되는것이다!



다른 용도는 커맨드 객체 초기화 부분이다.
@ModelAttribute 어노테이션을 사용하면, 커맨드 객체의 초기화 작업을 수행할 수도 있다.
그럴수 밖에... 
@Controller
@RequestMapping("/account/create.do")
public class CreateAccountController {

@ModelAttribute("command")
public MemberInfo formBacking(HttpServletRequest request) {
if (request.getMethod().equalsIgnoreCase("GET")) {
MemberInfo mi = new MemberInfo();
Address address = new Address();
address.setZipcode(autoDetectZipcode(request.getRemoteAddr()));
mi.setAddress(address);
return mi;
} else {
return new MemberInfo();
}
}

private String autoDetectZipcode(String remoteAddr) {
return "000000";
}

@RequestMapping(method = RequestMethod.GET)
public String form() {
return "account/creationForm";
}

@RequestMapping(method = RequestMethod.POST)
public String submit(@ModelAttribute("command") MemberInfo memberInfo,
BindingResult result) {
new MemberInfoValidator().validate(memberInfo, result);
if (result.hasErrors()) {
return "account/creationForm";
}
return "account/created";
}
}

GET/POST 각각의 요청에 따라 객체 초기화가 가능하다.
위에서보면 submit 시의 command 가 바로 @ModelAttribute("command") 의 객체를 가르키게 된다.
왜냐면 @ModelAttribute 어노테이션이 적용된 메소드가 @RequestMapping 어노테이션이 적용된 메소드보다 먼저 호출되므로,
초기화 작업처럼 되는것이다.

그리고 ModelAttribute 어노테이션이 적용된 메소드는 RequestMapping 어노테이션이 적용된 메소드와 동일한 타입의 파라미터를 가질 수 있다.
 @ModelAttribute("command")
public MemberInfo formBacking(HttpServletRequest request) {

HttpServletRequest 말고도 Locale, @RequestParam 어노테이션 적용, @PathVariable 어노테이션등을 적용가능하다. 
 



'IT > 스프링' 카테고리의 다른 글

PathVariable 어노테이션을 이용한 URI 템플릿...  (0) 2012.01.16
URI 매칭.. (서블릿 맵핑)  (0) 2012.01.13
모델 생성.... (Model )  (0) 2012.01.13
@Controller 어노테이션... - 1 -  (0) 2012.01.10
filter....  (0) 2012.01.10
@RequestMapping 어노테이션이 적용된 메소드의 파라미터나 리턴타입으로 ModelAndView, Model, ModelMap, Map, 커맨드 객체 등을 이용해서 모델을 뷰에 전달하게 된다.

컨트롤러가 모델을 어떻게 뷰에 전달하는 지 살펴보도록 하자.

1.1 뷰에 전달되는 모델 데이터

        @RequestMapping("/search/game.do")
public ModelAndView search(@ModelAttribute("command") SearchCommand command, ModelMap model) {
                String[] queryList = getPopularQueryList();
                model.addAttribute("popularQueryList", queryList);
                 
ModelAndView mav = new ModelAndView("search/game");
SearchResult result = searchService.search(command);
mav.addObject("searchResult", result);
return mav;
}
 
근데 이상하다... model 자체를 리턴하지 않는데도 이게 뷰까지 간단 말야..
그리고 mav 도 별도로 또 가고 -ㅅ- 뭐야 이거

-->
 @ModelAttribute 를 메소드에 적용하면 해당 메소드가 생성한 객체가 뷰에 전달된다!!!!
아하.. 그래서 return 에 없는 객체들을 jsp 에서 참조가능했구나!!!!!!



즉.. JSP 에서 호출할때
${searchResult}, ${command.query} , ${popularQueryList} 로 접근된다.... ;;


1.2 Map, Model, ModelMap 을 통한 모델설정.. 

모델의 메소드에 대해서 잠깐 언급하자면,
Model, ModelMap 의 경우는 addAttribute 로 값을 설정하고, Map 이야.. put
그리고 Model은 인터페이스이다.   ExtendedModelMap 으로 할당해서 보통 쓴다.

1.3 ModelAndView 
 ModelAndView야 .. 뭐
    -setViewName() 을 통한 뷰 이름 설정
    -addObject(xxx,xxx) 를 이용한 전달값 추가
    -ModelAndView(뷰이름,맵) 생성자를 통한 뷰이름,Map 데이터 전달 






















 




'IT > 스프링' 카테고리의 다른 글

URI 매칭.. (서블릿 맵핑)  (0) 2012.01.13
@ModelAttribute  (2) 2012.01.13
@Controller 어노테이션... - 1 -  (0) 2012.01.10
filter....  (0) 2012.01.10
DispatcherServlet... more  (0) 2012.01.10
흐음... 
우선.. 리다이렉트 302(http)  는 리다이렉트의 내용을 의미한다.
즉, 그 내용은 브라우저의 history에 남지 않는다. (여기서 리다이렉트는 html 레벨이 아닌 서블릿이나.. 그런 레벨의 redirect 임)

http 200 이 브라우저의 history로 남더라.



즉 구매페이지는 200 으로 보여졌고 history에 쌓였고,
중간 구매액션페이지에서 리다이렉트로 완료페이지로 보냈다면,  구매액션페이지는 302
완료페이지는 200 으로 떨어진다.

실제 확인해보면 history.length 는 구매페이지, 구매완료페이지 해서 2로 나온다.

물론 패킷캡쳐해보면 중간 구매액션페이지는 302로 잡히긴한다. 


=============================

추가로 

jsp 에서 response.sendredirect 를 기술해놓으면 
해당페이지는 302 처리되어 history에 쌓이지 않는다.(redirect.jsp 가 302로 안남음)

다만 이동 목표 b.html 은 히스트로에 쌓인다.

목표url이 주소로 바뀌어있다. (즉 주소가 바뀜)


jsp 에서
RequestDispatcher dispatcher = request.getRequestDispatcher(url);
dispatcher.forward(request, response);
위와같이 forward 로 history에도 쌓이지 않는다. 
브라우저 상의 주소는 바뀌지 않는다. 
(패킷에 forward.jsp 403 만 남음)
목표 페이지가 히스토리에 남지 않는다. (왜냐면 주소변화가 없으니까)

+ Recent posts