sprignMVC详细总结

链接:https://www.cnblogs.com/sunniest/p/4555801.html
链接:https://blog.youkuaiyun.com/striner/article/details/80442500
链接:https://blog.youkuaiyun.com/shuaicihai/article/details/63052757
链接(上传文件):https://www.cnblogs.com/fjsnail/p/3491033.html
一、SpringMVC基础入门
1.首先,导入SpringMVC需要的jar包。
在这里插入图片描述
2. web.xml中进行请求拦截映射, 具体可以看spring的内容:https://blog.youkuaiyun.com/qq_40303031/article/details/89225041

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>springMVC</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 
  <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springMVC.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>
  1. 新建一个springMVC配置文件,选中常用的命名空间:beans aop context mvc

注意,名字要跟web.xml中的<param-value>classpath:springMVC.xml</param-value>匹配

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<!-- 文件扫描器 -->
	<context:component-scan base-package="org.wajpzywj.hander"></context:component-scan>
	
	<!-- 视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

  1. 在控制层处理请求,
package org.wajpzywj.hander;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
// 声明该类被扫描,将会创建bean,实例化
@Controller
public class SpringMVCHander {
	// RequestMapping表示处理这个请求。
	@RequestMapping("welcome")
	public String welcome() {
		// 默认使用请求转发的跳转方式
		return "success";
	}

}
  1. 在WebContext目录中创建index.jsp测试文件
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<a href="welcome">first springmvc</a>
</body>
</html>
  1. 在WebContext目录中创建views文件夹,里面创建success.jsp文件
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	welcomo to my springmvc;
</body>
</html>
  1. 启动tomcat,进行测试;

二、配置解析
10. Dispatcherservlet

DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据相应的规则分发到目标Controller来处理,是配置spring MVC的第一步。

  1. InternalResourceViewResolver

视图名称解析器

  1. 以上出现的注解

@Controller

负责注册一个bean 到spring 上下文中

@RequestMapping

注解为控制器指定可以处理哪些 URL 请求

三、SpringMVC常用注解

@Controller

负责注册一个bean 到spring 上下文中

@RequestMapping

注解为控制器指定可以处理哪些 URL 请求

@RequestBody

该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上
,再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上

@ResponseBody

该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区

@ModelAttribute

在方法定义上使用 @ModelAttribute 注解:Spring MVC
在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute 的方法

在方法的入参前使用 @ModelAttribute 注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数
–绑定到对象中,再传入入参将方法入参对象添加到模型中

@RequestParam

在处理方法入参处使用 @RequestParam 可以把请求参 数传递给请求方法

@PathVariable

绑定 URL 占位符到入参

@ExceptionHandler

注解到方法上,出现异常时会执行该方法

@ControllerAdvice

使一个Contoller成为全局的异常处理类,类中用@ExceptionHandler方法注解的方法可以处理所有Controller发生的异常

三、@RequestMapping

使用注意事项:

  1. 参数类型

@RequestMapping(value="welcome", method=RequestMethod.POST, params = {"name=zs"})
里面可以约束,请求的地址,请求方法,请求参数
age!=23:
a. 如果有name=“age”, 则age值不能是23
b. 没有age
!name2 :表示不能包含参数name2,否则报错

  1. ant风格的请求路径

?单字符
* 任意个字符(0或者多个)
** 任意目录

@RequestMapping(value=“welcome/**/test”)
接受示例:“welcome/abc/xyz/abbc/test”

四、RESTFul风格的SringMVC

  1. 在web.xml中添加配置
<!-- 增加HiddenHttpMethodFilter过滤器:目的是给普通浏览器增加put和delete请求方式 -->
<filter>
	<filter-name>HiddenHttpMethodFilter</filter-name>
	<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>HiddenHttpMethodFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
  1. 在前台index.jsp可以用以下代码产生请求
<!-- restful风格 -->
<form action="rest/user/1" method="post">
     <input type="hidden" name="_method" value="PUT">
     <input type="submit" value="put">
 </form>
 
 <form action="rest/user/1" method="post">
     <input type="submit" value="post">
 </form>
 
 <form action="rest/user/1" method="get">
     <input type="submit" value="get">
 </form>
 
 <form action="rest/user/1" method="post">
     <input type="hidden" name="_method" value="DELETE">
     <input type="submit" value="delete">
 </form>
  1. 控制层处理请求
package org.wajpzywj.hander;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/rest")
public class SpringMVCHander {
	
	@RequestMapping(value="/user/{id}",method=RequestMethod.GET)
    public String get(@PathVariable("id") Integer id){
        System.out.println("get"+id);
        return "/hello";
    }
    
    @RequestMapping(value="/user/{id}",method=RequestMethod.POST)
    public String post(@PathVariable("id") Integer id){
        System.out.println("post"+id);
        return "/hello";
    }
    
    @RequestMapping(value="/user/{id}",method=RequestMethod.PUT)
    public String put(@PathVariable("id") Integer id){
        System.out.println("put"+id);
        return "/hello";
    }
    
    @RequestMapping(value="/user/{id}",method=RequestMethod.DELETE)
    public String delete(@PathVariable("id") Integer id){
        System.out.println("delete"+id);
        return "/hello";
    }

}

注意点:

  1. 必须是post方式
  2. 通过隐藏域的value值 设置实际的请求方式 delete/put
  3. 通过 method=RequestMethod.PUT 匹配具体的请求方式

原理:

原始请求: request, 改请求默认只支持get,post
但是如果是"POST", 并且有隐藏域,则过滤器将原始的请求request加入新的请求方式delete,并将原始请求转为 requestToUse请求(request+delete)
最后将requestToUse 放入请求链中,
后续再实行request时,实际就是使用改造后的requestToUse

五、使用@RequestParam注解指定参数的name

@Controller
@RequestMapping("/test")
public class mvcController1 {
    @RequestMapping(value="/param")
    public String testRequestParam(@RequestParam(value="id") Integer id,
            , @RequestParam(value="age", required=false, defaultValue="23") Integer age){
        // 相当于 String name = request.getParameter("name")
        System.out.println(id+" "+name);
        return "/hello";
    }    
}

注意点:

@RequestParam(value=“name”):接受前台传递的值,等价于request.getParameter(“name”)
required=false: 该属性不是必须的
defaultValue=“23” : 默认值是23

获取头信息:使用方法同@RequestParam

@Controller
@RequestMapping("/test")
public class mvcController1 {
    @RequestMapping(value="/param")
    public String testRequestParam(@RequestHeader(value="Accept-Language") String al){
        System.out.println("Accept-Language:"+al);
        return "/hello";
    }    
}

获取cookie:使用方法同@RequestParam

@Controller
@RequestMapping("/test")
public class mvcController1 {
    @RequestMapping(value="/param")
    public String testRequestParam(@CookieValue(value="JSESSIONID") String jsessionId){
        System.out.println("JSESSIONID:"+jsessionId);
        return "/hello";
    }    
}

知识点:

(前置知识:服务端在接受客户端第一次请求时,会给客户端分配一个session(该session包含一个sessionId),并且服务端会在第一次相应客户端时,请该sessionId赋值给JSESSIONID 并传递给客户端的cookie中)

小结:

sprignMVC处理各种参数的流程:

  1. 请求:前段发请求a -> @RequestMapping(“a”)
  2. 处理请求中的参数xyz:
    @RequestMapping(“a”)
    public String aa(@Xxx注解(“xyz”) xyz){}

六、自动装箱

使用对象(实体类Student)接受请求参数

student属性必须和form表单中的属性name值一致(支持级联属性)

  1. 编写一个Student实体类和 Address实体类
package org.wajpzywj.entity;
public class Student {
	private int id;
	private String name;
	private Address address;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", address=" + address + "]";
	}
}

package org.wajpzywj.entity;
public class Address {
	private String homeAddress;
	private String schoolAddress;
	public String getHomeAddress() {
		return homeAddress;
	}
	public void setHomeAddress(String homeAddress) {
		this.homeAddress = homeAddress;
	}
	public String getSchoolAddress() {
		return schoolAddress;
	}
	public void setSchoolAddress(String schoolAddress) {
		this.schoolAddress = schoolAddress;
	}
}

  1. 前台请求表单
<form action="testObjectProperties" method="post">
	id:<input name="id" type="text">
	name:<input name="name" type="text">
	homeAddress:<input name="address.homeAddress" type="text">
	schoolAddress:<input name="address.schoolAddress" type="text">
	<input type="submit" value="提交"/>
</form>
  1. 在Controller里编写方法
@RequestMapping(value="testObjectProperties")
public String welcome(Student student) {// student属性必须和form表单中的属性name值一致(支持级联属性)
	System.out.println(student);
	return "success";
}

七、在springMVC中使用原生态的Servlet API:HttpServletRequest:

直接将servlet-api中的类,接口等 写在springMVC所映射的方法参数中即可:

@RequestMapping(value="testObjectProperties")
public String welcome11(HttpServletRequest request, HttpServletResponse response) {
	request.getParameter("name");
	return "success";
}

八、ModelAndView处理模型数据

如果跳转时需要带数据:V,M,则可以使用以下方式:
ModelAndView, ModelMap, Map, Model
1. 数据放在了request作用域

@SessionAttributes , @ModelAttribute

  1. 控制层
@RequestMapping(value="testModelAndView")
// ModelAndView既有模型,又有视图
public ModelAndView testModelAndView() {
	ModelAndView mv = new ModelAndView("success");
	Student student = new Student();
	student.setId(1);
	student.setName("zs");
	// 相当于 request.setAttribute("student", student);
	mv.addObject("student",student);
	return mv;
}
  1. success.jsp怎么取出属性,

${requestScope.student.id}-${requestScope.student.name}

以上的控制层的方法可以这样写: 完全等价。

@RequestMapping(value="testModelMap")
public String testModelMap(ModelMap mm) {
	Student student = new Student();
	student.setId(1);
	student.setName("zs");
	mm.put("student",student);
	return "success";
}

@RequestMapping(value="testMap")
public String testMap(Map<String,Object> map) {
	Student student = new Student();
	student.setId(1);
	student.setName("zs");
	map.put("student",student);
	return "success";
}

@RequestMapping(value="testModel")
public String testModel(Model model) {
	Student student = new Student();
	student.setId(1);
	student.setName("zs");
	model.addAttribute("student",student);
	return "success";
}

2. 数据放在了session作用域

  • 控制层 : 主要更改最上面的注解
package org.wajpzywj.hander;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.wajpzywj.entity.Student;

@Controller
@RequestMapping("/rest")
@SessionAttributes(value="student4") //(放一个)如果要在request域中存放student4对象,则同时将该对象放在session域中
//@SessionAttributes(types={Student.class}) //(放一批)如果要在request域中存放Student类型的对象,则同时将该对象放在session域中
public class SpringMVCHander {
	
	@RequestMapping(value="testModelAndView")
	// ModelAndView既有模型,又有视图
	public ModelAndView testModelAndView() {
		ModelAndView mv = new ModelAndView("success");
		Student student = new Student();
		student.setId(1);
		student.setName("zs");
		// 相当于 request.setAttribute("student", student);
		mv.addObject("student1",student);
		return mv;
	}
	
	
	
	@RequestMapping(value="testModelMap")
	public String testModelMap(ModelMap mm) {
		Student student = new Student();
		student.setId(1);
		student.setName("zs");
		mm.put("student2",student);
		return "success";
	}
	
	@RequestMapping(value="testMap")
	public String testMap(Map<String,Object> map) {
		Student student = new Student();
		student.setId(1);
		student.setName("zs");
		map.put("student3",student);
		return "success";
	}
	
	@RequestMapping(value="testModel")
	public String testModel(Model model) {
		Student student = new Student();
		student.setId(1);
		student.setName("zs");
		model.addAttribute("student4",student);
		return "success";
	}

}

  • 视图层:success.jsp这样检测
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	request域<br>
	${requestScope.student1.id}-${requestScope.student1.name}<br>
	${requestScope.student2.id}-${requestScope.student2.name}<br>
	${requestScope.student3.id}-${requestScope.student3.name}<br>
	${requestScope.student4.id}-${requestScope.student4.name}<br>
	
	session域<br>
	${sessionScope.student1.id}-${sessionScope.student1.name}<br>
	${sessionScope.student2.id}-${sessionScope.student2.name}<br>
	${sessionScope.student3.id}-${sessionScope.student3.name}<br>
	${sessionScope.student4.id}-${sessionScope.student4.name}<br>
	
</body>
</html>

九、@ModelAttribute 使用

作用:

  1. 经常在更新时使用
  2. 在不改变原有代码的基础上,插入一个新方法。
//在任何一次请求前都会执行@ModelAttribute修饰的方法
@ModelAttribute
public void queryStudentById(Map<String,Object> map) {
	// StudentService stuService = new StudentService();
	// Student student = stuService.queryStudentById(23);
	Student student = new Student();
	student.setId(33);
	student.setName("ls");
	// 约定:map的key就是 方法参数 类型的首字母小写
	map.put("student", student);
}

@RequestMapping(value="testModelAttribute")
public String testModelAttribute(Student student) {
	student.setName("小红书");
	System.out.println(student);
	return "success";
}

如果不一致,也可以使用注解,本质一样。

//在任何一次请求前都会执行@ModelAttribute修饰的方法
@ModelAttribute
public void queryStudentById(Map<String,Object> map) {
	// StudentService stuService = new StudentService();
	// Student student = stuService.queryStudentById(23);
	Student student = new Student();
	student.setId(33);
	student.setName("ls");
	// 约定:map的key就是 方法参数 类型的首字母小写
	// map.put("student", student);
	map.put("stu",student);
}

@RequestMapping(value="testModelAttribute")
public String testModelAttribute(@ModelAttribute("stu") Student student) {
	student.setName("小红书");
	System.out.println(student);
	return "success";
}

小结:

通过@ModelAttribute修饰的方法,会在每次请求前先执行;
并且该方法的参数map.put()可以将 对象放入即将查询的参数中;
必须满足的约定:
map.put(k, v) 其中的k, 必须是即将查询的方法参数的首字母小写
testModelAttribute(Student xxx), 即student;

十、国际化

  1. 视图, 视图解析器
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"></property>
	<property name="suffix" value=".jsp"></property>
</bean>

常见的视图和解析器:

InternalResourceView, InternalResourceViewResolver

public class JstlView extends InternalResourceView:
springMVC解析jsp时,会默认使用InternalResourceView, 如果发现jsp中包含了jstl语言,则自动转为JstlView

  1. 实现国际化

JstlView 可以解析jstl,实现国际化操作

1. 创建资源文件

格式: 基名_语言_地区.properties
基名_语言.properties

2. 配置springMVC.xml, 加载资源文件
<!-- 加载国际化资源文件 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basename" value="i18n"></property>
</bean>

重点:

  1. 将ResourceBundleMessageSource在程序加载:springMvc:springMVC 在启动时,会自动查找一个 id=“messageSource” 的bean, 如果有,则自动加载;
  2. 如果配置了ResourceBundleMessageSource, 则该类会在程序响应时介入
  3. 将以i18n开头的所有文件都加载。
3. 通过jstl使用国际化
  1. jar包:

jstl.jar
standard.jar
在这里插入图片描述

  1. 控制层,一定经过控制层,才能加载到id=“messageSource” 的bean
@RequestMapping(value="testI18n")
public String testI18n() {
	return "success";
}
  1. 写properties文件,需要以配置中写道的value值开头的文件,此处是i18n开头的文件
    在这里插入图片描述
    跟据不同的名字写上不同的值:
resource.welcome=\u6B22\u8FCE
resource.exist=\u9000\u51FA
  1. 视图层
    引入标签:是jstl的fmt标签,不要弄错了
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<fmt:message key="resource.welcome"></fmt:message><br>
<fmt:message key="resource.exist"></fmt:message>

十一、视图解析器 其他功能

正常流程:

index.jsp => Controller(@RequestMapping) => succes.jsp

要用SpringMVC实现:

index.jsp => success.jsp:

如何实现,不经过控制层,跳转页面?
答:只需配置上一下的话,即可进行跳转

第一步:

<!-- view-name会被视图解析器加上前缀和后缀 -->
<mvc:view-controller path="rest/testMvcViewController" view-name="success"/>

问题:以上注解,会让所有的请求 转入<mvc:..>中匹配映射地址,而会忽略调用@RequestMapping();

如果想要@RequestMapping(“a”)和mvc:.. 共存,则需要加入一个注解:

第二步:

<!-- 此注解是mvc基础配置,很多功能都需要该注解来协调 -->
<mvc:annotation-driven></mvc:annotation-driven>

十二、在Controller中使用redirect方式处理请求

指定跳转方式:

return “forward:/views/success.jsp”;
return “redirect:/views/success.jsp”;

需要注意:

  1. 此种方式不会被视图解析器加上前缀和后缀。
  2. 默认是转发,
  3. forward是转发,redirect是重定向

十三、静态资源访问

在springMvc中, 如果直接访问静态资源:404.
原因:

所有的请求 通过通配符"/" 拦截,进而交给springMVC的入口DispatcherServlet去处理:
找该请求映射对应的@RequestMapping
http://localhost:8888/SpringMVCProject/img.png
@RequestMapping(“img.png”)
没有对应的@RequestMapping(“img.png”);从而报错

解决:

  1. 交给springMVC的@RequestMapping(“img.png”)处理。 // 自行处理
  2. 不用sprignMVC处理,则使用tomcat默认的Servlet去处理

servlet怎么处理?

如果有对应的请求拦截,则交给相应的Servlet去处理;如果没有对应的servlet,则直接访问。
tomcat默认的Servlet在哪里?在tomcat配置文件\conf\web.xml中

终极实现方案:只需要增加两个配置即可
<!-- 该注解会让springMVC,接收一个请求,并且该请求没有对应的@RequestMapping的时候,将该请求交给服务器默认的servlet去处理(直接访问) -->
<mvc:default-servlet-handler/>

<!-- 此注解是mvc基础配置,很多功能都需要该注解来协调 -->
<mvc:annotation-driven></mvc:annotation-driven>

直接访问图片,不需要重启服务,图片放在WebContent文件下面。
在这里插入图片描述
十四、类型转换

  1. spring自带一些 常见的类型转换器:

public String testDelete(@PathVariable(“id”) String id),
即可以接受int类型数据id, 也可以接受String类型数据

  1. 可以自定义类型转换器
    2.1. 编写自定义类型转换器的类(实现Converter接口)
package org.wajpzywj.conterver;

import org.springframework.core.convert.converter.Converter;
import org.wajpzywj.entity.Student;

public class MyConverter implements Converter<String, Student>{

	@Override
	public Student convert(String source) {
		String[] studentStrArr = source.split("-");
		Student student = new Student();
		student.setId(Integer.valueOf(studentStrArr[0]));
		student.setName(studentStrArr[1]);
		return student;
	}
}

2.2. 将转换器MyConverter配置到springMVC中去

<!-- 1. 将自定义转换器纳入SpringIOC容器 -->
<bean id="myConverter" class="org.wajpzywj.conterver.MyConverter"></bean>
<!-- 2. 将myConverter再纳入SpringMVC提供的转换器Bean -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="converters">
		<set>
			<ref bean="myConverter"/>
		</set>
	</property>
</bean>
<!-- 3. 将conversionService注册到annotation-driven中 -->	
<!-- 此注解是mvc基础配置,很多功能都需要该注解来协调 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

2.3. 测试转换器

前端index.jsp代码:

<form action="rest/testConverter" method="post">
	student-infos:<input type="text" name="studentInfo">
	<input type="submit" value="converter"/>
</form>

控制层

@RequestMapping(value="testConverter")
public String testConverter(@RequestParam("studentInfo")Student student) { // 前段:44-zs
	System.out.println(student);
	return "redirect:/views/success.jsp";
}
实现原理:

其中@RequestParam(“studentInfo”)是触发转换器的桥梁
@RequestParam(“studentInfo”)接收的数据 是前段传递过来的:23-lisi;
但是需要将该数据复制给修饰的目的对象Student; 因此SpringMVC 可以发现接受的数据和目标数据不一致,并且这两种数据分别是String,Student, 正好符合public Student myconvert(String source)转换器

3. 数据格式化:日期格式

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")

3.1 配置

<!-- 配置数据格式化 注解 所依赖的bean -->
<bean id="ConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>

3.2 在类属性上加上注解

@NumberFormat(pattern="###,#")
private int id;

// 格式化前端传递来的数据,将前端传递来的数据固定为yyyy-MM-dd
@DateTimeFormat(pattern="yyyy-MM-dd")

3.3 写index.jsp页面

<form action="rest/testDateTimeFormat" method="post">
	id:<input type="text" name="id" value="32">
	name:<input type="text" name="name">
	birthday:<input type="text" name="birthday">
	<input type="submit" value="format"/>
</form>
<br>

3.4 写控制层

@RequestMapping(value="testDateTimeFormat")// 如果格式化错误,会将错误的信息传入result
public String testDateTimeFormat(Student student, BindingResult result) {
	System.out.println(student);
	if(result.getErrorCount() > 0) {
		for(FieldError error : result.getFieldErrors()) {
			System.out.println(error.getDefaultMessage());
		}
	}
	return "redirect:/views/success.jsp";
}

注意:

  1. BindingResult 是第二参数,当格式化错误的时候,自动将错误传入此参数,
  2. BindingResult 可以没有不写
重点

观察一下代码:

<!-- 1. 将自定义转换器纳入SpringIOC容器 -->
<bean id="myConverter" class="org.wajpzywj.conterver.MyConverter"></bean>
<!-- 2. 将myConverter再纳入SpringMVC提供的转换器Bean -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="converters">
		<set>
			<ref bean="myConverter"/>
		</set>
	</property>
</bean>
<!-- 3. 将conversionService注册到annotation-driven中 -->	
<!-- 此注解是mvc基础配置,很多功能都需要该注解来协调 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

<!-- 配置数据格式化 注解 所依赖的bean -->
<bean id="ConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
FormattingConversionServiceFactoryBean既能实现格式化,又可以实现类型转换,可以完全替代ConversionServiceFactoryBean
<!-- FormattingConversionServiceFactoryBean既能实现格式化,又可以实现类型转换,可以完全替代ConversionServiceFactoryBean -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"></bean>

可以写成这样:

<!-- 1. 将自定义转换器纳入SpringIOC容器 -->
<bean id="myConverter" class="org.wajpzywj.conterver.MyConverter"></bean>
<!-- 2. 将myConverter再纳入SpringMVC提供的转换器Bean -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
	<property name="converters">
		<set>
			<ref bean="myConverter"/>
		</set>
	</property>
</bean>
<!-- 3. 将conversionService注册到annotation-driven中 -->	
<!-- 此注解是mvc基础配置,很多功能都需要该注解来协调 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

以上例子将错误信息打印在控制台,怎么将错误信息显示在前台?

思路:如果要将控制台的错误消息 传到jsp中显示,则可以将错误消息对象放入request域中,然后再jsp中,从request域中获取

  1. 修改控制层: 注意BindingResult只能放在修饰的对象后面,否则报错
@RequestMapping(value="testDateTimeFormat")// 如果格式化错误,会将错误的信息传入result
public String testDateTimeFormat(Student student, BindingResult result, Map<String,Object> map) {
	System.out.println(student);
	if(result.getErrorCount() > 0) {
		// 将错误信息放到request作用域里面,让前台可以取到 
		map.put("errors", result.getFieldErrors());
		for(FieldError error : result.getFieldErrors()) {
			System.out.println(error.getDefaultMessage());
		}
	}
	return "success";
}
  1. 修改success.jsp页面
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:forEach items="${requestScope.errors}" var="error">
	${error.getDefaultMessage()}
</c:forEach>

十五、表单的验证(使用Hibernate-validate)

Hibernate-validate 是JSR303的扩展,包含JSR303的所有功能,并且有其他新添加的功能

  1. jar包
hibernate-validator.jar
classmate.jar
jboss-logging.jar
validatetion-api.jar
hibernate-validator-annotation-processor.jar

注意版本问题:
在这里插入图片描述
版本问题可能不兼容,出现错误,可以参考:https://lanqiao.coding.me/springmvc框架/SpringMVC-lesson27

  1. 配置:
<mvc:annotation-driven></mvc:annotation-driven>

作用:

  1. 要实现Hibernate Validator/JSR303校验(或者其他各种校验), 必须实现接口:ValidatorFactory
  2. LocalValidatorFactoryBean是ValidatorFactory的一个实现类。
  3. <mvc:annotation-driven></mvc:annotation-driven>会在springMVC容器中 自动加载一个LocalValidatorFactoryBean类,可以直接实现数据校验。
  1. 使用
    1. 在属性前面加上注解
    2. 在校验的Controller中,给校验的对象前增加 @Valid

例子:

  1. 创建user类。
package org.wajpzywj.entity;

import java.util.Date;

import javax.validation.constraints.Past;

import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;

public class User {
	private int id;
    @NotEmpty
    private String name;

    @Past
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date birth;
	
	public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getBirth() {
        return birth;
    }
    public void setBirth(Date birth) {
        this.birth = birth;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", birth=" + birth + "]";
    }    
    
}

  1. 前端:index.jsp
<form action="form/add" method="post">
	id:<input type="text" name="id" value="32">
	name:<input type="text" name="name">
	birthday:<input type="text" name="birth">
	<input type="submit" value="format"/>
</form>
  1. 控制层
package org.wajpzywj.hander;

import java.util.Map;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.wajpzywj.entity.User;

@Controller
@RequestMapping("/form")
public class formController {
    @RequestMapping(value="add",method=RequestMethod.POST)    
    public String add(@Valid User u,BindingResult result, Map<String,Object> map){
    	System.out.println(u);
        if(result.getErrorCount()>0){            
        	for(FieldError error : result.getFieldErrors()) {
				System.out.println(error.getDefaultMessage());
				map.put("errors", result.getFieldErrors());
			}
        }
        return "forward:/views/success.jsp";
    }
    
}

十六、使用Ajax调用

  1. jar包

jackson-annotations.jar
jackson-core.jar
jackson-databind.jar

注意版本要一致
在这里插入图片描述
2. 控制层

// 告诉springMVC, 此时返回的不是一个View页面,而是一个ajax调用的返回值
@ResponseBody
@RequestMapping(value="testJson")
public List<Student> testJson() {
	System.out.println(123);
	Student stu1 = new Student(1,"zhangsan");
	Student stu2 = new Student(2,"lisi");
	Student stu3 = new Student(3,"wangwu");
	List<Student> students = new ArrayList<>();
	students.add(stu1);
	students.add(stu2);
	students.add(stu3);
	return students;
}
  1. 前端 ajax 调用
<script type="text/javascript" src="js/jquery-3.3.1.js"></script>
<script type="text/javascript">
$(document).ready(function(){
	 $("#testJson").click(function(){
		 alert("22");
		 // 通过ajax请求springMVC
		 $.post(
			// 服务器地址
			"rest/testJson", //服务器地址
			function(result){ // 服务端处理完毕后的回调函数LIst<Student> students,
			// 加上@ResponseBody后, students实质是一个json数组的格式
				for(var i=0;i<result.length;i++){
					alert(result[i].id +"---"+ result[i].name);
				}
			}
		 );
	 });
});
</script>

<input type="button" value="testJson" id="testJson"/>

十七、文件上传
链接:https://lanqiao.coding.me/springmvc框架/SpringMVC-lesson30
链接:https://www.cnblogs.com/fjsnail/p/3491033.html

本质:和servlet一样

springMVC可以简化文件上传的代码,但是必须满足条件:
实现MultipartResolver接口
该接口的实现类springMvc已经提供了CommonsMultipartResolver
(直接使用CommonsMultipartResolver实现上传)

  1. jar包

commons-fileupload.jar
commons-io.jar

在这里插入图片描述
2. 配置 CommonsMultipartResolver

<!-- 配置CommonsMultipartResolver,实现文件上传,springIOC容器初始化的时候,会自动查找id=multipartResolver的bean,并加入ioc容器中 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="defaultEncoding" value="UTF-8"></property>
	<property name="maxUploadSize" value="10240000"></property>
</bean>
  1. 控制层
@RequestMapping(value="testFileUpload")
public String testFileUpload(@RequestParam("desc") String desc, @RequestParam("file") MultipartFile file) throws IOException {// student属性必须和form表单中的属性name值一致(支持级联属性)
	System.out.println("文件的描述信息:"+desc);
	// jsp中上传的文件:file
	InputStream input = file.getInputStream();
	String fileName = file.getOriginalFilename();
	OutputStream output = new FileOutputStream("C:\\E\\"+fileName);
	int len=0;
	byte[]arr=new byte[1024];
	while((len=input.read(arr)) != -1) {
		output.write(arr, 0, len);
	}
	output.close();
	input.close();
	// 将file上传到服务器中的某一个硬盘文件中。
	return "success";
}
  1. 前端jsp
<form action="rest/testFileUpload" method="POST" enctype="multipart/form-data">
	 文件: <input type="file" name="file"/>
	  描述: <input type="text" name="desc"/>
	  <input type="submit" value="Submit"/>
</form>

十八、设置一个自定义拦截器

  1. 创建一个MyInterceptor类,并实现HandlerInterceptor接口
package org.wajpzywj.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyIntercepter implements HandlerInterceptor{

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("拦截请求");
		// true 拦截之后放行,false拦截之后不放行
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("拦截相应");
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("视图(jsp)被渲染完毕");
	}
}
  1. 在SpringMVC的配置文件中配置
<!-- 将自己写的拦截器配置到springMvc中 -->
<mvc:interceptors>
	<!-- 配置具体的拦截路径 -->
	<mvc:interceptor>
		<!-- 指定拦截路径,可以使用ant风格 -->
		<mvc:mapping path="/**"/>
		<!-- 指定不拦截的路径 -->
		<mvc:exclude-mapping path="/rest/testFileUpload"/>
		<bean class="org.wajpzywj.interceptor.MyIntercepter"></bean>
	</mvc:interceptor>
</mvc:interceptors>

也可以拦截所有请求:

<!-- 将自己写的拦截器配置到springMvc中,默认拦截所有请求 -->
<mvc:interceptors>
	<bean class="org.wajpzywj.interceptor.MyIntercepter"></bean>
</mvc:interceptors>
  1. 拦截器执行顺序
    在这里插入图片描述
    十九、异常的处理

链接:https://lanqiao.coding.me/springmvc框架/SpringMVC-lesson31

1. 处理局部异常(Controller内)
package org.wajpzywj.hander;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("second")
public class SecondSpringMVCHandler {
	@RequestMapping("testExceptionHandler")
	public String testExceptionHandler() {
		System.out.println(1/0);
		return "success";
	}
	
	// 该方法可以捕获本类中出现的 一些异常,放入到requestScope域中,
	@ExceptionHandler({ArithmeticException.class, ArrayIndexOutOfBoundsException.class})
	public ModelAndView handlerArithmeticException(Exception e) {
		ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", e);
		System.out.println(e);
		return mv;
	}
	
}

  1. 处理全局异常(所有Controller)
package org.wajpzywj.hander;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class testControllerAdvice {
	
	@ExceptionHandler
    public ModelAndView exceptionHandler(Exception ex){
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", ex);
        System.out.println("in testControllerAdvice");
        return mv;
    }

}

  1. 另一种处理全局异常的方法

在SpringMVC配置文件中配置

<!-- SimpleMappingExceptionResolver配置的方式处理异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<!-- 如果发生异常,异常对象会保存在exceptionAttribute的value中 ,并且会放在requestScope域中-->
	<property name="exceptionAttribute" value="e"></property>
       <property name="exceptionMappings">
           <props>
               <prop key="java.lang.ArithmeticException">error</prop>
               <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
           </props>
       </property>
   </bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值