SpringMVC request processing

1. Configuration of request mapping path

Only by configuring the mapping path can the mapper processor find the method resources of the Controller. Currently, the mainstream mapping path configuration method is @RequestMapping

insert image description here

The @RequestMapping annotation is mainly used in the method of the controller to identify the path for the client to access resources. Commonly used attributes include value, path, method, headers, params, etc. When @RequestMapping has only one access path to specify, use the value attribute, path attribute or omit value and path. When there are multiple attributes, value and path cannot be omitted

@RequestMapping(value = "/show")//使用value属性指定一个访问路径
public String show(){
    
    }
@RequestMapping(value = {
    
    "/show","/haohao","/abc"})//使用value属性指定多个访问路径
public String show(){
    
    }

@RequestMapping(path = "/show")//使用path属性指定一个访问路径
public String show(){
    
    }
@RequestMapping(path = {
    
    "/show","/haohao","/abc"})//使用path属性指定多个访问路径
public String show(){
    
    }

@RequestMapping("/show")//如果只设置访问路径时,value和path可以省略
public String show(){
    
    }
@RequestMapping({
    
    "/show","/haohao","/abc"})
public String show(){
    
    }

When @RequestMapping needs to limit the access method, it can be set through the method attribute

//请求地址是/show,且请求方式必须是POST才能匹配成功
@RequestMapping(value = "/show",method = RequestMethod.POST)
public String show(){
    
    }

The attribute value of method is an enumeration type, the source code is as follows:

public enum RequestMethod {
    
    
	GET,
	HEAD,
	POST,
	PUT,
	PATCH,
	DELETE,
	OPTIONS,
	TRACE;
	private RequestMethod() {
    
    
	}
}

@GetMapping, when the request method is GET, we can use @GetMapping instead of @RequestMapping

@GetMapping("/show")
public String show(){
    
    }

@PostMapping, when the request method is POST, we can use @PostMapping instead of @RequestMapping

@PostMapping("/show")
public String show(){
    
    }

@RequestMapping is used on the class, @RequestMapping, @GetMapping, @PostMapping can also be used on the Controller class, after being used on the class, all methods of this class share the attributes set by the @RequestMapping, and the access path is the mapping on the class address + mapped address on the method, for example:

@Controller
@RequestMapping("/xxx")
public class UserController implements ApplicationContextAware, ServletContextAware {
    
    
	@GetMapping("/aaa")
	public ModelAndView aaa(HttpServletResponse response) throws IOException, ModelAndViewDefiningException {
    
    
		return null;
	}
}

The access path at this time is: /xxx/aaa

2. Receiving request data

1. Receive common request data

To receive normal request data, when the data submitted by the client is in the form of normal key-value pairs, just use the formal parameter with the same name to receive it directly
username=haohao&age=35

@GetMapping("/show")
public String show(String username, int age){
    
    
	System.out.println(username+"=="+age);
	return "/index.jsp";
}

To receive normal request data, when the name of the request parameter is inconsistent with the name of the method parameter, you can use the @RequestParam annotation to mark
username=haohao&age=35

@GetMapping("/show")
public String show(@RequestParam(name = "username",required = true) String name, int age){
    
    
	System.out.println(name+"=="+age);
	return "/index.jsp";
}

2. Receive array or collection data

Receive an array or collection of data. When the client passes multiple parameters with the same name, you can use an array to receive
hobbies=eat&hobbies=sleep

@GetMapping("/show")
public String show(String[] hobbies){
    
    
	for (String hobby : hobbies) {
    
    
		System.out.println(hobby);
	}
	return "/index.jsp";
}

When the client passes multiple parameters with the same name, it can also be received with a single-column collection, but @RequestParam needs to be used to inform the framework that the passed parameters should be set with the same name, not object properties

@GetMapping("/show")
public String show(@RequestParam List<String> hobbies){
    
    
	for (String hobby : hobbies) {
    
    
		System.out.println(hobby);
	}
	return "/index.jsp";
}

To receive array or collection data, when the client passes multiple parameters with different names, you can also use Map<String, Object> to receive them, and you also need to use @RequestParam to modify
username=haohao&age=18

@PostMapping("/show")
public String show(@RequestParam Map<String,Object> params) {
    
    
	params.forEach((key,value)->{
    
    
		System.out.println(key+"=="+value);
	});
	return "/index.jsp";
}

3. Receive entity JavaBean attribute data

Receive entity JavaBean attribute data, single JavaBean data: as long as the submitted parameter name is consistent with the Java attribute name, it can be automatically encapsulated
username=haohao&age=35&hobbies=eat&hobbies=sleep

public class User {
    
    
	private String username;
	private Integer age;
	private String[] hobbies;
	private Date birthday;
	private Address address;
	//... 省略get和set方法 ... 
}
@GetMapping("/show")
public String show(User user) {
    
    
	System.out.println(user);
	return "/index.jsp";
}

Receive entity JavaBean attribute data, nest JavaBean data: the submitted parameter name can be used to describe the attribute relationship of the nested object
username=haohao&address.city=tianjin&address.area=jinghai

public class Address {
    
    
    private String city;
    private String area;
    //... 省略get和set方法 ... 
}
// http://localhost/param6?username=haohao&address.city=tianjin&address.area=jinghai
@GetMapping("/param6")
public String param6(User user){
    
    
    System.out.println(user);
    return "/index.jsp";
}

4. Receive Json data format data

To receive data in Json data format, Json data is submitted in the form of a request body, and is not in the original key-value pair format, so we need to use the @RequestBody annotation to receive the data as a whole.

{
    
    
	"username":"haohao",
	"age":18,
	"hobbies":["eat","sleep"],
	"birthday":"1986-01-01",
	"address":{
    
    
		"city":"tj",
		"area":"binhai"
	}
}
@PostMapping("/show6")
public String show6(@RequestBody String body){
    
    
	System.out.println(body);
	return "/index.jsp";
}

Use the Json tool ( jackson ) to convert the string in Json format into JavaBean for operation

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.9.0</version>
</dependency
@PostMapping("/show")
public String show(@RequestBody String body) throws IOException {
    
    
	System.out.println(body);
	// 获得ObjectMapper
	ObjectMapper objectMapper = new ObjectMapper();
	// 将json格式字符串转化成指定的User
	User user = objectMapper.readValue(body, User.class);
	System.out.println(user);
	return "/index.jsp";
}

Configure the RequestMappingHandlerAdapter and specify the message converter, so you don't need to manually convert the json format string

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="messageConverters">
		<list>
		<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
		</list>
	</property>
</bean>
@PostMapping("/show")
public String show(@RequestBody User user){
    
    
	System.out.println(user);
	return "/index.jsp";
}

Receive Json data format data, use Map to receive json format string

@PostMapping("/show")
public String show(@RequestBody Map map){
    
    
	System.out.println(map);
	return "/index.jsp";
}

5. Receive Restful style data

What is Rest style?
Rest (Representational State Transfer) representational state transition (representational state transition), was proposed in 2000, based on standards and protocols such as HTTP, URI, xml, and JSON, and supports lightweight, cross-platform, and cross-language architecture design. It is a new web application design style and development method for web services.

For Restful style requests, the common rules are as follows:

① Use URI to represent a module resource, and the resource name is a noun
insert image description here
② Use the request method to represent the specific business action of the module

For example: GET means query, POST means insert, PUT means update, DELETE means delete

insert image description here
③ Use the HTTP response status code to indicate the result

, the commonly used responses in China include three parts: status code, status information, and response data

{
    
    
	"code":200,
	"message":"成功",
	"data":{
    
    
		"username":"haohao",
		"age":18
	}
}

{
    
    
	"code":300,
	"message":"执行错误",
	"data":"",
}

Receive Restful style data, Restful request data is generally carried on the URL address, you can use the annotation @PathVariable (placeholder parameter name)
http://localhost/user/100

@PostMapping("/user/{id}")
public String findUserById(@PathVariable("id") Integer id){
    
    
	System.out.println(id);
	return "/index.jsp";
}

The request URL resource address contains multiple parameters
http://localhost/user/haohao/18

@PostMapping("/user/{username}/{age}")
public String findUserByUsernameAndAge(@PathVariable("username") String username, @PathVariable("age") Integer age){
    
    
	System.out.println(username+"=="+age);
	return "/index.jsp";
}

To receive the uploaded data, the file upload form needs certain requirements, as follows:
⚫ The submission method of the form must be POST
⚫ The enctype attribute of the form must be multipart/form-data
⚫ The file upload item must have a name attribute

<form action="" enctype="multipart/form-data" method="post" >
	<input type="file" name="myFile">
</form>

On the server side, since the mapper adapter requires a file upload parser, which is not registered by default, manual registration is required

<!--配置文件上传解析器,注意:id的名字是固定写法,id必须是multipartResolver,因为Spring容器是根据id="multipartResolver"获取的CommonsMultipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="defaultEncoding" value="UTF-8"/><!--文件的编码格式 默认是ISO8859-1-->
	<property name="maxUploadSizePerFile" value="1048576"/><!--上传的每个文件限制的大小 单位字节-->
	<property name="maxUploadSize" value="3145728"/><!--上传文件的总大小-->
	<property name="maxInMemorySize" value="1048576"/><!--上传文件的缓存大小-->
</bean>

The Apache used at the bottom of the CommonsMultipartResolver is the file uploading by tool APIs such as Common-fileuplad, so the following dependencies must be imported

<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.4</version>
</dependency>

Use the MultipartFile type to receive uploaded files

@PostMapping("/fileUpload")
public String fileUpload(@RequestBody MultipartFile myFile) throws IOException {
    
    
	System.out.println(myFile);
	// 获得上传的文件的流对象
	InputStream inputStream = myFile.getInputStream();
	// 使用commons-io存储到C:\haohao\abc.txt位置
	FileOutputStream outputStream = new 
	FileOutputStream("C:\\Users\\haohao\\" + myFile.getOriginalFilename());
	IOUtils.copy(inputStream,outputStream);
	// 关闭资源
	inputStream.close();
	outputStream.close();
	return "/index.jsp";
}

Receive Http request header data, receive the request header with the specified name

@GetMapping("/headers")
public String headers(@RequestHeader("Accept-Encoding") String acceptEncoding){
    
    
	System.out.println("Accept-Encoding:" + acceptEncoding);
	return "/index.jsp";
}

Receive all request header information

@GetMapping("/headersMap")
public String headersMap(@RequestHeader Map<String,String> map){
    
    
	map.forEach((k,v)->{
    
    
	System.out.println(k+":"+v);
	});
	return "/index.jsp";
}

Obtain the cookie data carried by the client

@GetMapping("/cookies")
public String cookies(@CookieValue(value = "JSESSIONID",defaultValue = "") String jsessionid){
    
    
	System.out.println(jsessionid);
	return "/index.jsp";
}

Obtain and forward the data in the Request field. When forwarding between resources, sometimes it is necessary to store some parameters in the request field and carry them to the next resource

@GetMapping("/request1")
public String request1(HttpServletRequest request){
    
    
	// 存储数据
	request.setAttribute("username","haohao");
	return "/request2";
}

@GetMapping("/request2")
public String request2(@RequestAttribute("username") String username){
    
    
	System.out.println(username);
	return "/index.jsp";
}

For the solution of garbled request parameters, Spring has provided a good CharacterEncodingFilter for encoding filtering

<!--配置全局的编码过滤器-->
<filter>
	<filter-name>CharacterEncodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>CharacterEncodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

3. Javaweb Common Object Acquisition

To obtain common native objects of Javaweb, sometimes we need to use native objects of Javaweb in our Controller method, such as: Request, Response, etc. We only need to write the required objects in the form of formal parameters on the method, and the SpringMVC framework calls the Controller method, the actual parameters are automatically passed:

@GetMapping("/javawebObject")
public String javawebObject(HttpServletRequest request, HttpServletResponse response, HttpSession session){
    
    
	System.out.println(request);
	System.out.println(response);
	System.out.println(session);
	return "/index.jsp";
}

4. Request static resources

The reason for the failure of static resource requests is that when the mapping path of DispatcherServlet is configured as /, then the default default Servlet of the Tomcat container is overwritten. There is a web.xml in the Tomcat config directory, which is the global configuration for all web projects. , which has the following configuration:

<servlet>
	<servlet-name>default</servlet-name>
	<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

The Servlet whose url-pattern is configured as / is called the default Servlet. Its function is to find the default Servlet when other Servlets are not matched successfully. Since there is no matching Servlet for static resources, the default Servlet will be found. DefaultServlet, the DefaultServlet has the function of matching static resources twice. But we overwrite it after configuring DispatcherServlet, and DispatcherServlet will match the name of the requested static resource as the mapping path of the Controller, that is, the access to the static resource is unsuccessful!

Three solutions for static resource requests:

  1. In the first solution, Tomcat’s DefaultServlet can be activated again. The matching priority of Servlet’s url-pattern is: exact match>directory match>
    extension match>default match, so you can specify the url-pattern in a certain directory or a certain extension Resources are parsed using the DefaultServlet
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>/img/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>*.html</url-pattern>
</servlet-mapping>
  1. The second way is to configure static resource mapping in spring-mvc.xml, and match the request of the mapping path to the specified location to match the resource
<!-- mapping是映射资源路径,location是对应资源所在的位置 -->
<mvc:resources mapping="/img/*" location="/img/"/>
<mvc:resources mapping="/css/*" location="/css/"/>
<mvc:resources mapping="/css/*" location="/js/"/>
<mvc:resources mapping="/html/*" location="/html/"/>
  1. The third way is to configure <mvc:default-servlet-handler> in spring-mvc.xml. This way is to register a DefaultServletHttpRequestHandler processor, and access to static resources is handled by this processor, which is also under development. most used
<mvc:default-servlet-handler/>

5. Annotation-driven <mvc:annotation-driven> tag

The second and third methods of static resource configuration We can access the static resource normally, but the Controller cannot access it again, and an error 404 is reported, that is, the corresponding resource cannot be found

insert image description here

The second way is to use SpringMVC to analyze the static resource analysis completed by the resources tag under the mvc namespace. The third way is to use SpringMVC to analyze the static resource analysis completed by the default-servlet-handler tag under the mvc namespace. According to the previous From the knowledge of the resolution of the custom namespace learned, it can be found that no matter which method is used above, the SimpleUrlHandlerMapping will eventually be registered

public BeanDefinition parse(Element element, ParserContext context) {
    
    
	// 创建SimpleUrlHandlerMapping类型的BeanDefinition
	RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
	// 注册SimpleUrlHandlerMapping的BeanDefinition
	context.getRegistry().registerBeanDefinition(beanName, handlerMappingDef);
}

Combined with the component analysis knowledge points mentioned before, once there is a HandlerMapping type component in the SpringMVC container, the front controller DispatcherServlet will get the HandlerMapping from the container when it is initialized, and the default processor mapping in dispatcherServlet.properties will no longer be loaded The server strategy means that RequestMappingHandlerMapping will not be loaded, so the @RequestMapping annotation will not be parsed.

Therefore, it is necessary to manually register RequestMappingHandlerMapping in the SpringMVC container, so that when DispatcherServlet is initialized, it will simultaneously obtain RequestMappingHandlerMapping from the container and store it in the List collection named handlerMappings in DispatcherServlet to parse the @RequestMapping annotation.

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

According to the above explanation, it can be summarized that if we want to use @RequestMapping to map to resource methods normally, and at the same time, static resources can be accessed normally, and we can freely convert between request json format strings and JavaBean, we need to use spring-mvc Configure the following in .xml:

<!-- 显示配置RequestMappingHandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 显示配置RequestMappingHandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="messageConverters">
		<list>
			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
		</list>
	</property>
</bean>
<!--配置DefaultServletHttpRequestHandler-->
<mvc:default-servlet-handler/>

Does such a complicated and cumbersome configuration seem a bit big? Spring is a "warm man". It condenses the above configuration into a simple configuration tag, which is the annotation driver of mvc. The tag will help us register RequestMappingHandlerMapping, register RequestMappingHandlerAdapter and inject Json message converter, etc. The above configuration can be simplified into the following:

<!--mvc注解驱动-->
<mvc:annotation-driven/>
<!--配置DefaultServletHttpRequestHandler-->
<mvc:default-servlet-handler/>

PS: The < mvc:annotation-driven> tag registers different components in different versions. The Spring 3.0.X version registration is
DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter. Due to the development of the framework, the registered component from Spring 3.1.X becomes RequestMappingHandlerMapping and RequestMappingHandlerAdapter

Guess you like

Origin blog.csdn.net/qq_36602071/article/details/129785619