Spring MVC common annotations / exception handling

Keywords: Java Attribute Session Spring

Catalog

I @ Requestmapping

Map multiple URI s

The value and path attributes have the same function and can be interchanged. There is only one attribute, which can be omitted.

    @RequestMapping(value = {
            "/a","/b","/c"
    })
    public String multi(){
        return "multi";
    }

method attribute

Can receive one or more RequestMethod enumerations

    @RequestMapping(value = "/post",method = RequestMethod.POST)
    public String post(){
        return "post";

    }

    @RequestMapping(value = "/get",method = RequestMethod.GET)
    public String get(){
        return "get";

    }

    @RequestMapping(value = "/getOrPost",method = {RequestMethod.GET,RequestMethod.POST})
    public String getOrPost(){
        return "getOrPost";

    }

params attribute

This attribute represents the request parameters, which must be passed in the request (can be placed in the url or request body)

    @RequestMapping(path = "/login", params={"username=kolbe","password=123456"})
    public String login() {
        return "success";
    }

headers property

    @RequestMapping(path = "/header", headers="Accept-Language=zh-CN")
    public String header() {
        return "success";
    }

    @RequestMapping(path = "/header2", headers={"Accept-Language=zh-CN","Accept=text/html"})
    public String header2() {
        return "success";
    }

Support for ant style

Ant style resource address supports three matching characters:

  • ?: matches a character in the filename –
  • *: matches any character in the filename –
  • **: match multiple paths
    @RequestMapping(path = "/ant/*")
    public String ant() {
        return "success3";
    }

    @RequestMapping(path = "/ant/?")
    public String ant1() {
        return "success1";
    }

    @RequestMapping(path = "/ant/**")
    public String ant2() {
        return "success2";
    }

Ranking according to test priority:? > * > * *: summary is that the more specific the priority is, the higher (a common programming idea)

Two @ PathVariable

Is a new feature of spring 3.0

//@PathVariable can be used to map placeholders in URL s to parameters in the target method
	@RequestMapping("/testPathVariable/{id}")
    public String testPathVariable(@PathVariable("id") Integer id)
    {
        System.out.println("testPathVariable:"+id);
        return SUCCESS;
    }

Three rest style

Because browser forms only support GET and POST requests, in order to implement DELETE and PUT requests, Spring provides us with a filter org.springframework.web.filter.HiddenHttpMethodFilter, which can transform GET and POST requests into DELETE and PUT requests through the filter.

Configuring filters in web.xml

<!-- To configure org.springframework.web.filter.HiddenHttpMethodFilter Filter -->
<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>    
<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <!-- Block all requests -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

Because the browser form cannot send the DELETE and PUT requests, in order for HiddenHttpMethodFilter to recognize the request method, it is necessary to add a hidden field in the form, whose name is ﹐ method value is DELETE or POST or PUT, and the code of the modified index.jsp page is as follows:

    <form action="user" method="post">
	    <input type="hidden" name="_method" value="POST"/>
		<input type="submit" value="Test Rest POST"/>
	</form>
	
	<!-- delete id 1. user -->
	<form action="user/1" method="post">
		<input type="hidden" name="_method" value="DELETE"/>
		<input type="submit" value="Test Rest DELETE"/>
	</form>
	
	<!-- To update id 1. user -->
	<form action="user/1" method="post">
		<input type="hidden" name="_method" value="PUT"/>
		<input type="submit" value="Test Rest PUT"/>
	</form>

IV @ RequestHeader, @ CookieValue

@The RequestHeader annotation can bind the value of the Request header part to the parameter of the method.

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,
                              @RequestHeader("Keep-Alive") long keepAlive)  {
 
  //...
 
}

@Cookie value can bind the cookie value in the Request header to the parameter of the method.

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie)  {
 
  //...
 
}

5. sessionattributes

Reference resources: springmvc Basics (19): use of @ SessionAttributes annotation

  • If you want to share data among multiple requests, you can mark a @ SessionAttributes on the controller class, configure the data range that needs to be stored in the session, and Spring MVC will store the corresponding data in the model and temporarily store it in HttpSession.
  • @SessionAttributes can only be used on class definitions.
  • @SessionAttributes can not only specify the attributes to be put into the session by attribute name, but also specify which model attributes to put into the session by object type of model attributes, for example:
    1. @SessionAttributes(types=User.class) adds all attributes of type User in the model to the session.
    2. @SessionAttributes(value = {"user1", "user2"}) will add the attributes named user1 and user2 in the model to the session.
    3. @SessionAttributes(types={User.class, Dept.class}) will add all attributes of type User and dept in the model to the session.
    4. @SessionAttributes(value = {"user1", "user2"}, types={Dept.class}) will add the attributes named user1 and user2 in the model and the attributes of type Dept to the session.
@SessionAttributes(value={"user"})
@Controller
public class UserController {

    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Model model){
        User user = new User("jack","123456");
        model.addAttribute("user", user);
        return "success";
    }
}

user will be placed not only in the attribute of request, but also in the attribute of session.

Scavenging mode

public ModelAndView test(SessionStatus status) {
  status.setComplete();
   ...
}

Only the parameters saved to the session through @ SessionAttribute will be deleted

Six @ ModelAttribute

Reference resources: https://blog.csdn.net/huawuque004/article/details/81586914
Specific usage examples
Before calling the request method, put some default values in the (map) implicit model according to the parameters

    @ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
                        Map<String, Object> maps){
        System.out.println("getUser");
        if(id != null){
           Person p = new Person();
           p.setName("zhuyc");
            maps.put("person",p);//Here, the key is paid attention to. For example, the mode1 method wants to get the value. Key must be Person lowercase
        }
    }

    @RequestMapping("/mode1")
    public String mode1(Person p1){
        System.out.println("mode1");
        System.out.println(p1.getName());
        return "mode1";
    }

    @RequestMapping("/mode2")
    public String mode2(@ModelAttribute("person")Person p1){//Match pattern 2 below
        System.out.println("mode1");
        System.out.println(p1.getName());
        return "mode1";
    }

Be careful

  1. @The methods decorated by ModelAttribute will be executed in advance by spring MVC and run before each target method.
  2. Match pattern 1: the key stored in the map needs to be consistent with the lowercase string of the first letter of the input parameter type of the target method
  3. Match pattern 2: decorate with annotation ModelAttribute and set the value attribute value to point to the key name in your map

Find the attribute value corresponding to attrName in implicit model, and use it if it exists. If not, verify that the current Handler uses @ SessionAttribute to decorate the class. If @ SessionAttribute is used, try to get the value corresponding to attrName from HttpSession. If there is no corresponding value in Session, an exception will be thrown. [this is also a common problem caused by the use of SessionAttribute and ModelAttribute]. If the current Handler does not use the @ SessionAttribute modifier class, and the key specified by the value value value does not match the attrName in @ SessionAttribute, the POJO object is created through the reflection mechanism.

1. If not, a new POJO class will be created (very common)

    @ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
                        Map<String, Object> maps){
        System.out.println("getUser");
        if(id != null){
//           Person p = new Person();
//           p.setName("zhuyc");
//            maps.put("person",p);
            System.out.println("testput");
        }
    }

    @RequestMapping("/mode1")
    public String mode1(Person p1){
        System.out.println("mode1");
        System.out.println(p1.getName());
        return "mode1";
    }

=====output====
getUser
testput
mode1
null

2. Throw an exception (request mode2 first)

@SessionAttributes(value={"person"})
@Controller
@RequestMapping("/ma")
public class ModelAttributeDemoController {


     @ModelAttribute//This method does not affect the conclusion
    public void getUser(@RequestParam(value="id",required=false) Integer id,
                        Map<String, Object> maps){
        System.out.println("getUser");
        if(id != null){
//           Person p = new Person();
//           p.setName("zhuyc");
//            maps.put("person",p);
            System.out.println("testput");
        }
    }

    @ResponseBody
    @RequestMapping("/mode2")
    public String mode2(@ModelAttribute("person")Person p1){
        System.out.println("mode2");
        System.out.println(p1.getName());
        return "mode1";
    }

    @RequestMapping("/model1")
    public ModelAndView model1(ModelAndView modelAndView){
        Person p = new Person();
        p.setName("asdsadasdas");
        modelAndView.addObject("person",p);
        modelAndView.setViewName("m");
        return modelAndView;
    }

====The result is wrong, but it should be executed first. model1 It doesn't matter====
org.springframework.web.HttpSessionRequiredException: Expected session attribute &#39;person&#39;
	org.springframework.web.method.annotation.ModelFactory.initModel(ModelFactory.java:115)
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:810)
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743)
	org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

3. Once the value of @ SessionAttributes on the class is different from that of @ ModelAttribute, no such value and no error will be reported.

@SessionAttributes(value={"person1"})
@Controller
@RequestMapping("/ma")
public class ModelAttributeDemoController {
    ...
  
    @ResponseBody
    @RequestMapping("/mode2")
    public String mode2(@ModelAttribute("person")Person p1){
        System.out.println("mode2");
        System.out.println(p1.getName());
        return "mode1";
    }
    

7. Exception handling

There are three ways of Spring unified exception handling, namely:

  • Use @ ExceptionHandler annotation
  • Implement HandlerExceptionResolver interface
  • Use @ controlleradvice annotation

@ExceptionHandler annotation

Write in a class (not recommended)

@Controller      
public class GlobalController {               

   /**    
     * For handling exceptions    
     * @return    
     */      
    @ExceptionHandler({MyException.class})       
    public String exception(MyException e) {       
        System.out.println(e.getMessage());       
        e.printStackTrace();       
        return "exception";       
    }       

    @RequestMapping("test")       
    public void test() {       
        throw new MyException("Wrong!");       
    }                    
}

Implement HandlerExceptionResolver

@Component  
public class ExceptionTest implements HandlerExceptionResolver{  

    /**  
     * TODO Briefly describe the implementation function of the method (optional).  
     * @see org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)  
     */   
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,  
            Exception ex) {  
        System.out.println("This is exception handler method!");  
        return null;  
    }  
}

@ControllerAdvice with @ ExceptionHandler()

It is recommended that different exceptions can be handled in different ways conveniently.

@RestControllerAdvice
public class GlobalExceptionHandler {

	// Abnormal information
	// @ResponseStatus
	@ExceptionHandler(ResultException.class)
	public WebResult msgExceptionHandler(ResultException ex) {
		ex.printStackTrace();
		String message = ex.getLocalizedMessage();
		if (StringUtils.empty(message))
			return new WebResult(0);
		return new WebResult(1000, ex.getMessage(), null);
	}

	@ResponseStatus(HttpStatus.UNAUTHORIZED)
	@ExceptionHandler(BadCredentialsException.class)
	public WebResult msgExceptionHandler(BadCredentialsException ex) {
		ex.printStackTrace();
		return new WebResult(4);
	}
	
	@ExceptionHandler(ValidateException.class)
	public WebResult validationException1(ValidateException ex) {
		
		return new WebResult(5,ex.getInfos());
	}

//	@ExceptionHandler(ConstraintViolationException.class)
//	public WebResult msgExceptionHandler(ConstraintViolationException ex) {
//		ex.printStackTrace();
//		return new WebResult(11);
//	}
//
//	@ExceptionHandler(DataIntegrityViolationException.class)
//	public WebResult msgExceptionHandler(DataIntegrityViolationException ex) {
//		ex.printStackTrace();
//		return new WebResult(11);
//	}

	@ExceptionHandler({ RollbackException.class, MySQLIntegrityConstraintViolationException.class, DataIntegrityViolationException.class,ConstraintViolationException.class })
	public WebResult sqlException(Exception ex) {
		ex.printStackTrace();
		return new WebResult(11);
	}

	// Runtime exception
	@ResponseStatus
	@ExceptionHandler(RuntimeException.class)
	public WebResult runtimeExceptionHandler(RuntimeException ex) {
		ex.printStackTrace();
		return new WebResult(1000, ex.getLocalizedMessage());
	}

	// Null pointer exception
	@ResponseStatus
	@ExceptionHandler(NullPointerException.class)
	public WebResult nullPointerExceptionHandler(NullPointerException ex) {
		ex.printStackTrace();
		return new WebResult(1001, ex.getMessage());
	}

	// Type conversion exception
	@ResponseStatus
	@ExceptionHandler(ClassCastException.class)
	public WebResult classCastExceptionHandler(ClassCastException ex) {
		ex.printStackTrace();
		return new WebResult(1002, ex.getMessage());
	}

	// IO anomaly
	@ResponseStatus
	@ExceptionHandler(IOException.class)
	public WebResult iOExceptionHandler(IOException ex) {
		ex.printStackTrace();
		return new WebResult(1003, ex.getMessage());
	}

	// Unknown method exception
	@ResponseStatus
	@ExceptionHandler(NoSuchMethodException.class)
	public WebResult noSuchMethodExceptionHandler(NoSuchMethodException ex) {
		ex.printStackTrace();
		return new WebResult(1004, ex.getMessage());
	}

	// Array out of bounds exception
	@ResponseStatus
	@ExceptionHandler(IndexOutOfBoundsException.class)
	public WebResult indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
		ex.printStackTrace();
		return new WebResult(1005, ex.getMessage());
	}

	// 400 mistake
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler({ HttpMessageNotReadableException.class })
	public WebResult requestNotReadable(HttpMessageNotReadableException ex) {
		ex.printStackTrace();
		return new WebResult(400, ex.getMessage());
	}

	// 400 mistake
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler({ TypeMismatchException.class })
	public WebResult requestTypeMismatch(TypeMismatchException ex) {
		ex.printStackTrace();
		return new WebResult(400, ex.getMessage());
	}
	...

VIII @ ResponseStatus

In Spring MVC application, we can set the status of HTTP response by using the annotation @ ResponseStatus.
Two species:

  • Used in the controller method
  • Used on exception classes

General usage

The common usage is set on the method:
as

	@RequestMapping("/hello")
    @ResponseBody
    @ResponseStatus(code = HttpStatus.OK)
    public String hello(){
        return "hello world";
    }

It can also be used in the exception handling section above

// 400 mistake
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler({ TypeMismatchException.class })
	public WebResult requestTypeMismatch(TypeMismatchException ex) {
		ex.printStackTrace();
		return new WebResult(400, ex.getMessage());
	}

Be careful

In addition to the class, you need to use the reason attribute. The above two uses do not need to use the reason attribute, otherwise Spring MVC will directly return an error page no matter what the method returns.

Reference

  1. @Details of RequestMapping usage
  2. @Details of parameter binding annotations such as RequestParam @RequestBody @PathVariable

Posted by Kingw on Sun, 27 Oct 2019 03:00:24 -0700