SpringMVC入门教程

包含如下所有的代码项目点这里javascript

目录html

1. 环境配置java

1.1 导入jar包jquery

1.2 xml配置web

2. 页面跳转ajax

2.1 实现代码spring

2.2 post编码统一express

3. 参数传递apache

4. 使用Maven构建项目json

4.1 基本构建

4.2 一些注解的使用

5. 数据回传

5.1 构建数据提交

5.2 数据回传方式

5.3 session注解的使用

6. 原生API

7. rest风格案例

7.1 处理静态资源

7.2 rest介绍

7.3 遍历数据

7.4 新增操做

7.5 删除操做

7.6 修改数据

8. SpringMVC执行原理

9. 自定义转换类型

10. json与jsonp

10.1 获取数据

10.2 提交数据

11. 异常处理

11.1 通常异常

11.2 自定义异常处理

11.3 全局异常

12. 简单拦截器

13. 文件上传


1. 环境配置

1.1 导入jar包

  • commons-logging-1.2.jar
  • jstl.jar
  • spring-aop-5.0.8.RELEASE.jar
  • spring-aspects-5.0.8.RELEASE.jar
  • spring-beans-5.0.8.RELEASE.jar
  • spring-context-5.0.8.RELEASE.jar
  • spring-core-5.0.8.RELEASE.jar
  • spring-expression-5.0.8.RELEASE.jar
  • spring-web-5.0.8.RELEASE.jar
  • spring-webmvc-5.0.8.RELEASE.jar

1.2 xml配置

web.xml基本配置以下:

<?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_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>SpringMVC-01-HelloWorld</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<!-- 中央控制器 (类比struts2的全局拦截器) -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<!-- DispatcherServlet主要用于控制流程 -->
		<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>
		<!-- 当值为0或者大于0时,表示容器在启动时就加载并初始化这个servlet -->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

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

根据上面的<servlet-name>springmvc</servlet-name>配置咱们还要在src下新建一个springmvc.xml配置以下:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
        <!--指定扫描controller -->
	<context:component-scan base-package="cn.itcast_01_springmvc.controller"></context:component-scan>
	<!-- 视图解析器 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
</beans>

其中"视图解析器"指明了要映射的jsp路径的结构目录,因此在WEB-INF下新建jsp文件夹放置jsp文件,在下面随便建一个jsp文件,命名为hello.jsp

新建cn.itcast_01_springmvc.controller以及Hello.java实例:

//通知spring须要扫描这个类,获得DispatchService解析
//注解至关于调用这个类,里面的参数至关于对应的构造方法
//访问路径名:http://localhost:8080/SpringMVC-01-HelloWorld/hello/world
//@Controller至关于<bean>注入,参考下面的struts2的<action>注入原理
@Controller
@RequestMapping("/hello")
public class Hello {
	//相似配置action,默认为method=RequestMethod.GET请求 
	@RequestMapping(value="/world")//,method=RequestMethod.POST
	public String hello() {
		System.out.println("hello");
		//返回要调用的jsp页面
		return "hello";
	}
}
//<package name="struct2" namespace="/" extends="struts-default">
//	<action name="hello" class="cn.itcast._01_hello.HelloAction" method="hello">
//		<result  type="dispatcher" name="good">hello.jsp</result>
//	</action>
//</package>

运行将会看到你的jsp页面

2. 页面跳转

2.1 实现代码

在Hello.java下添加以下的代码:

@RequestMapping(value="/loginForm")
public String loginFrom() {
	return "login";
}

在jsp下新建login页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="login" method="post">
帐号:<input name="user" />
密码:<input name="pass" />
<button>登录</button>
</form>
</body>
</html>

根据login页面咱们登录后要跳转到成功页面,因此提交到后台代码还要执行跳转页面:

@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(String user,String pass) {
	System.out.println("login"+user);
	return "redirect:world";
}

登录提交后重定向到刚才的Hello.jsp则跳转成功

2.2 post编码统一

在后台打印的中文发生乱码,解决方法以下:
在web.xml中新增节点:

<!-- 统一编码 -->
<filter>
	<filter-name>setcharacter</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>setcharacter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

3. 参数传递

新建UserController.java添加以下代码:

@Controller
public class UserController {
	@RequestMapping(value = "/list")
	public String list( Integer currentpage,Integer pagesize) {
		System.out.println("currentpage:" + currentpage);
		System.out.println("pagesize:" + pagesize);
		return "hello";
	}
}

你能够用以下方法测试并打印结果:

http://localhost:8080/SpringMVC-01-HelloWorld/list?currentpage=2&pagesize=100

固然要注意,若是不传值则会报null,用整形会报错,因此要用包装类Integer,还能够给参数设置默认值,方法改成:

@RequestMapping(value = "/list")
public String list(@RequestParam(value = "currentpage", defaultValue = "1") Integer currentpage,
		@RequestParam(value = "pagesize", defaultValue = "10") Integer pagesize) {
	System.out.println("currentpage:" + currentpage);
	System.out.println("pagesize:" + pagesize);
	return "hello";
}

你还能够用 @PathVariable(value="id")将链接字符拼接到url上

@RequestMapping("/get/{id}")
public String get(@PathVariable(value="id") Integer id){
	System.out.println("id:"+id);
	return "hello";
}

http://localhost:8080/SpringMVC-01-HelloWorld/get/1

4. 使用Maven构建项目

4.1 基本构建

须要安装Maven插件,eclipse自带可能版本太低,具体操做请见百度

新建项目二为SpringMVC-02-Mvn,利用pom.xml配置jar包(包含之后全部要用的jar包):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.itcast</groupId>
	<artifactId>SpringMVC-02-Mvn</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>5.0.8.RELEASE</spring.version>
	</properties>
	<dependencies>
		<!-- <dependency> -->
		<!-- <groupId>javax.servlet</groupId> -->
		<!-- <artifactId>servlet-api</artifactId> -->
		<!-- <version>2.5</version> -->
		<!-- <scope>provided</scope> -->
		<!-- </dependency> -->
		<!-- spring核心包 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- AOP aspect -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- JSTL标签类 -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- json -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.9.5</version>
		</dependency>
		<!-- jsonp -->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.5</version>
		</dependency>
		<!-- 下载 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.3</version>
		</dependency>

	</dependencies>
</project>

web.xml的DispatcherServlet配置与post编码照搬过来

springmvc.xml放在src/main/resources,代码照搬,但新增下面的代码:

<!-- 匹配注解驱动,要使用spring mvc中的@Controller注解,就必需要配置<mvc:annotation-driven /> -->
<!-- conversion-service注明了类型转换器 -->
<mvc:annotation-driven/>

在WEB-INF创建jsp文件夹和home.jsp,内容随意

新建cn.itcast_01_springmvc.controller和类IndexController.java

4.2 一些注解的使用

IndexController后台代码:

//获取cookie的内置参数值
@RequestMapping("/testCookie")
public String testCookie(@CookieValue("JSESSIONID") String sessionID) {
    System.out.println(sessionID);
    return "home";
}
// 获取一类请求头参数
@RequestMapping("/testHeader")
public String testHeader(@RequestHeader(value = "User-Agent") String header) {
	System.out.println(header);
	return "home";
}

// 跳转条件设置,pass等于10,跳转失败
@RequestMapping(value = "/testparam", params = { "user", "pass!=10" })
public String testParam(String user, Integer pass) {
	System.out.println(user + " " + pass);
	return "home";
}

//test前接受任意字符访问
@RequestMapping(value = "/*test")
public String test() {
	return "home";
}

5. 数据回传

5.1 构建数据提交

新建cn.itcast_01_springmvc.pojo和实体类:

public class Address {
	private Integer id;
	private String province;
	private String city;
//...
public class User {
	private Integer id;
	private String usern;
	private String pass;
	private String email;
	private Integer age;
	private Address address;
//...

在jsp下新建文件夹user和form.jsp(关于${sessionScope.str1}见5.3):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${sessionScope.str1}<br />
${sessionScope.str2}
<form action="save1">
帐号:<input name="usern" value="${user.usern}"><br />
密码:<input name="pass" value="${user.pass}"/><br />
年龄:<input name="age" value="${user.age}"/><br />
邮箱:<input name="email" value="${user.email}"/><br />
省份:<input name="address.province" value="${user.address.province}"/><br />
城市:<input name="address.city" value="${user.address.city}"/><br />
<button>注册</button>
</form>
</body>
</html>

控制层代码:

//Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的
//数据通过业务处理层处理以后封装成一个Model ,而后再把该Model 返回给对应的View 
//进行展现。在SpringMVC 中提供了一个很是简便的定义Controller 的方法,而后
//使用@RequestMapping 和@RequestParam 等一些注解用以定义URL请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。
@Controller
public class UserController {
	@Autowired
	private UserDao userDao;

@RequestMapping(value = "/form")
public String test() {
	return "user/form";
}

@RequestMapping(value = "/save1")
 public String save1(User user) {
    System.out.println(user.toString());
	return "home";
}

5.2 数据回传方式

后台代码增长:

// 将数据传到前台ModelAndView
	 @RequestMapping(value = "/edit1")
	 public ModelAndView edit1() {
	 User user = new User();
	 user.setUser("Bob");
	 user.setPass("123");
	 user.setAge(12);
	 user.setEmail("123@qq.com");
	 Address address = new Address();
	 address.setCity("成都");
	 address.setProvince("四川");
	 user.setAddress(address);
	 ModelAndView mv = new ModelAndView();
	 mv.setViewName("user/form");
	 mv.addObject("user", user);
	 return mv;
}	
	 // 将数据传到前台Map
	 @RequestMapping(value = "/edit2")
	 public String edit2(Map<String, Object> map) {
	 User user = new User();
	 user.setUser("Lisa");
	 user.setPass("123");
	 user.setAge(12);
	 user.setEmail("123@qq.com");
	 Address address = new Address();
	 address.setCity("成都");
	 address.setProvince("四川");
	 user.setAddress(address);
	 map.put("user", user);
	 return "user/form";
}	
	 // 将数据传到前台Model
         //这里将user的信息存入session,只字符存入session,固然这个注解能够放在类上面
         @SessionAttributes(value = { "user" }, types = { String.class })
	 @RequestMapping(value = "/edit3")
	 public String edit3(Model model) {
	 User user = new User();
	 user.setUser("Lucy");
	 user.setPass("123");
	 user.setAge(12);
	 user.setEmail("123@qq.com");
	 Address address = new Address();
	 address.setCity("成都");
	 address.setProvince("四川");
	 user.setAddress(address);
	 model.addAttribute("user", user);
	
	 model.addAttribute("str1", "session1");
	 model.addAttribute("str2", "session2");
	 return "user/form";
}

上面实现了三种方式的数据回传到form.jsp,通常使用Model

5.3 session注解的使用

上面的后台代码中,最后使用了 注解和model.addAttribute("str1", "session1");将值存入session,前面的前台代码利用EL表达式取出相应的值

6. 原生API

须要把tomcat的环境包build进来,包含

  1. HttpServletRequest
  2. HttpServletResponse
  3. HttpSession
  4. java.security.Principal
  5. Locale
  6. InputStream
  7. OutputStream
  8. Reader
  9. Writer

这里不作详讲,写个HttpSession测试类:

@Controller
public class HttpController {
	//内置api的session
	@RequestMapping("/http")
	public String http(HttpSession session) {
		System.out.println(session.getId());
		return "home";
	}
}

7. rest风格案例

7.1 处理静态资源

在webapp下新建lib文件夹,在lib下面新建js文件夹,引入jq文件jquery-3.3.1.min.js

在springmvc.xml中添加以下代码:

​<!--指定扫描dao -->
<context:component-scan base-package="cn.itcast_01_springmvc.dao"></context:component-scan>


<!-- 处理静态资源 -->
<!-- 若是遇到mapping路径,就去找到location -->
<mvc:resources location="/lib/" mapping="/lib/**" />

http://localhost:8080/SpringMVC-02-Mvn/lib/js/jquery-3.3.1.min.js

试着访问jq文件看可否成功

7.2 rest介绍

7.3 遍历数据

再web.xml中添加以下配置:

<!-- 用来过滤rest中的方法,在隐藏域中的put/delete方式,注意 因为执行顺序缘由  必定要放在编码过滤器下面,不然会出现编码问题 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        <init-param>
            <param-name>methodParam</param-name>
            <param-value>_method</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

新建cn.itcast_01_springmvc.dao以及UserDao.java以下:

@Repository("personDao")
public class UserDao {
	private static Map<Integer, User>users=null;
	
	static{
		users=new HashMap<Integer, User>();	
		users.put(1001, new User(1001,"Bob","123","123@qq.com",21,new Address(1,"黑龙江","哈尔滨")));
		users.put(1002, new User(1002,"Lucy","123","123@qq.com",21,new Address(1,"黑龙江","哈尔滨")));
		users.put(1003, new User(1003,"Lisa","123","123@qq.com",21,new Address(1,"黑龙江","哈尔滨")));
	}
	private Integer initId=1004;
	public void save(User user) {
		if (user.getId()==null) {
			user.setId(initId++);
		}
		users.put(user.getId(), user);
	}
	public Collection<User> getAll() {
		return users.values();
	}
	public User get(Integer id) {
		return users.get(id);
	}

	public void delete(Integer id) {
		users.remove(id);
	}
}

分别对应增长,遍历,查询,删除方法

在jsp下创建user文件夹,新建list.jsp(这里虽然有删除,修改等代码,但后文中会提示添加这些代码):

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>用户列表</h2>
	<table border="1" cellpadding="0" cellspacing="0">
		<tr>
			<td>id</td>
			<td>名字</td>
			<td>年龄</td>
			<td>操做</td>
		</tr>
		<c:forEach items="${userList}" var="s">
			<tr>
				<td>${s.id}</td>
				<td>${s.usern}</td>
				<td>${s.age}</td>
				<td><a href="javascript:void(0)" onclick="deleteById(${s.id})">删除</a>
					<a href="user/${s.id}">修改</a></td>
			</tr>
		</c:forEach>
	</table>

	<a href="user">增长</a>

	<form method="post" id="deleteForm">
		<input type="hidden" name="_method" value="DELETE" />
	</form>
</body>
<script
	src="${pageContext.request.contextPath}/lib/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
	function deleteById(id) {
		var form=document.getElementById("deleteForm");
		form.action="user/"+id;
		document.getElementById("deleteForm").submit();
	}
	function showdata(data) {
		console.log(data);
	}
</script>
<script
	src="http://localhost:8080/SpringMVC-02-Mvn/users-jsonp?callback=showdata"></script>
</html>

UserController.java的后台代码:

@Autowired
private UserDao userDao;

@RequestMapping(value = "/users", method = RequestMethod.GET)
public String list(Model model) {
	Collection<User> userList = userDao.getAll();
	model.addAttribute("userList", userList);
	System.out.println("users");
	//int a=Integer.parseInt("as");
	//int b=2/0;
	// 显示列表页
	return "user/list";
}

7.4 新增操做

后台代码新增:

// 保持restful风格,获取资源
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String add() {
	// 打开增长页
	return "user/add";
}

// 保持restful风格,新建资源
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String save(User user) {
	userDao.save(user);
	// 执行插入
	System.out.println(user);
	return "redirect:/users";
}

前台list.jsp代码添加"增长的a标签"

再新建add.jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form name="form1" action="${pageContext.request.contextPath}/user"
		method="post">
		帐号:<input name="usern" /><br /> 密码:<input name="pass" /><br /> 年龄:<input
			name="age" /><br /> 邮箱:<input name="email" /><br /> 省份:<input
			name="address.province" /><br /> 城市:<input name="address.city" /><br />
		<button>注册</button>
	</form>
</body>
</html>

这个页面点击注册保存数据回到首页

7.5 删除操做

前台list.jsp已经添加删除的代码

后台代码:

@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public String delete(@PathVariable(value = "id") Integer id) throws LackParamException {
	// 执行删除
	userDao.delete(id);
	return "redirect:/users";
}

7.6 修改数据

前台list.jsp已经添加修改的代码

须要添加edit.jsp以下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/${users.id }" method="post">
<input type="hidden" name="_method" value="PUT" />
<%-- <input type="hidden" name="id" value="${users.id }"/> --%>
帐号:<input name="usern" value="${users.usern}"><br />
密码:<input name="pass" value="${users.pass}"/><br />
年龄:<input name="age" value="${users.age}"/><br />
邮箱:<input name="email" value="${users.email}"/><br />
省份:<input name="address.province" value="${users.address.province}"/><br />
城市:<input name="address.city" value="${users.address.city}"/><br />
<button>保存</button>
</form>
</body>
</html>

后台代码新增:

@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public String edit(@PathVariable(value = "id") Integer id, Model model){
	User users = userDao.get(id);
	model.addAttribute("users", users);
	// 打开回显页
	return "/user/edit";
}

@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
public String update(@PathVariable(value = "id") Integer id, User users) {
	users.setId(id);
	userDao.save(users);
	// 执行更新
	return "redirect:/users";
}

8. SpringMVC执行原理

9. 自定义转换类型

自定义日期类型转换器

实体类User.java中添加以下属性:

private Date birthday;
//...

 在add.jsp中添加:

生日:<input name="birthday" /><br />

springmvc.xml添加(第一行是在原来的基础上改动):

<mvc:annotation-driven conversion-service="myConversion" />
<!-- 类型转换器 -->
<bean id="myConversion"
	class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
	<property name="converters">
		<set>
		    <bean class="cn.itcast_01_springmvc.converter.DateConverter"></bean>
		</set>
	</property>
</bean>

根据配置的<bean>的类会自动调用咱们自定义的类进行类型转换,因此咱们新建cn.itcast_01_springmvc.converter下新建DateConverter.java以下:

public class DateConverter implements Converter<String, Date> {
	@Override
	public Date convert(String source) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		sdf.setLenient(false);
		try {
			return sdf.parse(source);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}
}

最后点击添加在add.jsp输入日期时可输入2018-9-3这种格式

10. json与jsonp

JSON是一种基于文本的数据交换方式(不支持跨域),而JSONP是一种非官方跨域数据交互协议。

关于这两个的特色又是一大堆知识,详情百度

10.1 获取数据

在原来的基础上新增后台代码:

// @responseBody注解的做用是将controller的方法返回
// 的对象经过适当的转换器转换为指定的格式以后,写入到response对象的body区
@ResponseBody
@RequestMapping(value = "/users-json", method = RequestMethod.GET)
public Collection<User> listJson() {
    return userDao.getAll();
}
@RequestMapping(value = "/users-jsonp", method = RequestMethod.GET)
public void listJsonp(String callback, HttpServletResponse response) throws IOException {
	Collection<User> list = userDao.getAll();
	Gson gson = new Gson();
	String json = gson.toJson(list);
	response.getWriter().println(callback + "(" + json + ")");
}

以上就是将List集合的数据转为json格式

10.2 提交数据

利用ajax提交

add.jsp新增以下代码:

<h2>json</h2>
	<form name="form3" action="" method="post">
		帐号:<input id="usern" name="usern" value="${users.usern}"><br />
		密码:<input id="pass" name="pass" value="${users.pass}" /><br /> 年龄:<input
		id="age" name="age" value="${users.age}" /><br />
	<button type="button" id="saveBtn">保存</button>
</form>
<script
	src="${pageContext.request.contextPath}/lib/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
	$(function() {
		$("#saveBtn").click(function() {
			var str = {
				"usern" : $("#usern").val(),
				"pass" : $("#pass").val(),
				"age" : $("#age").val(),
			}
			$.ajax({
				url : "savejson",
				type : "post",
				contentType : "application/json;charset=utf-8",
				data : JSON.stringify(str)
			});
		});
	});
</script>

后台代码新增:

// 经过@requestBody能够将请求体中的JSON字符串绑定到相应的bean上
@RequestMapping(value = "/savejson", method = RequestMethod.POST)
public String saveJsonp(@RequestBody User users) throws IOException {
	System.out.println(users);
	userDao.save(users);
	return "redirect:/users";
}

运行查看你的json数据

11. 异常处理

11.1 通常异常

将原来的后台的遍历代码添加一个异常

@RequestMapping(value = "/users", method = RequestMethod.GET)
public String list(Model model) {
	Collection<User> userList = userDao.getAll();
	model.addAttribute("userList", userList);
	System.out.println("users");
	int b=2/0;
	return "user/list";
}

再添加异常处理:

@ExceptionHandler
public ModelAndView handleException(Exception e){
	System.out.println(e);
	ModelAndView mv=new ModelAndView();
	mv.setViewName("error");
	mv.addObject("exception",e);
	return mv;
}

在user文件夹下新建异常跳转页面error.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%=exception.getMessage() %>
${exception.message }
</body>
</html>

http://localhost:8080/SpringMVC-02-Mvn/users会跳转到异常并报错误信息

11.2 自定义异常处理

将刚才异常屏蔽,创建一个缺乏参数异常
新建包cn.itcast_01_springmvc.exception下新建异常处理代码:

public class LackParamException extends ServletException {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public LackParamException() {
		super("缺乏参数");
	}

	public LackParamException(String msg) {
		super(msg);
	}
}

 后台代码新增:

//自定义异常测试
@RequestMapping(value = "/test_exception")
public String testException(String str) throws LackParamException {
		if (org.springframework.util.StringUtils.isEmpty(str)) {
		throw new LackParamException();
	}
	return "home";
}

http://localhost:8080/SpringMVC-02-Mvn/test_exception?str=w带参数则不会报错 

11.3 全局异常

springmvc.xml添加:

<!--指定扫描exception -->
<context:component-scan base-package="cn.itcast_01_springmvc.exception"></context:component-scan>

 在这个包下再新建一个异常处理类:

//表示出现异常查就插入通知
@ControllerAdvice
public class MyExceptionHandler {

	@ExceptionHandler(Exception.class)
	public ModelAndView handleException(Exception e) {
		System.out.println("全场异常"+e);
		ModelAndView mv = new ModelAndView();
		mv.setViewName("error");
		mv.addObject("exception", e);
		return mv;
	}
}

再将遍历代码异常打开观察结果

12. 简单拦截器

新建cn.itcast_01_springmvc.interceptor下新建拦截器代码:

public class Myinterceptor1 implements HandlerInterceptor {
	/**
	 * 在执行Handler以前执行,用于身份校验,权限认证,返回true表示通行 false表示拦截
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("preHandle1");
		return true;
	}

	/**
	 * 在执行Handler时返回ModelAndView以前执行
	 * 若是想要向也买你提供一些公共数据或者一些公共的配置性信息,能够考虑使用这里的modelAndView
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle1");
	}

	/**
	 * 在执行Handler以后执行
	 * 日志,系统性能分析
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion1");
	}
}

你能够再复制一个同样的,取名为Myinterceptor2

接下来配置两次拦截,在springmvc.xml中注册:

<!-- 配置拦截器 -->
<mvc:interceptors>
	<!-- 配置多个拦截器 顺序执行 -->
	<mvc:interceptor>		
		<!-- /** 是拦截全部的文件夹及里面的子文件夹 -->
		<mvc:mapping path="/**" />
		<!-- 不拦截静态资源 -->
		<mvc:exclude-mapping path="/lib/**" />
		<bean class="cn.itcast_01_springmvc.interceptor.Myinterceptor1"></bean>
	</mvc:interceptor>
	<mvc:interceptor>
		<mvc:mapping path="/**" />
		<mvc:exclude-mapping path="/lib/**" />
		<bean class="cn.itcast_01_springmvc.interceptor.Myinterceptor2"></bean>
	</mvc:interceptor>
</mvc:interceptors>

运行遍历数据页面查看打印内容

13. 文件上传

我直接贴出springmvc.xml以上包括新增全部配置:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
	<!--指定扫描controller -->
	<context:component-scan base-package="cn.itcast_01_springmvc.controller"></context:component-scan>
	<!--指定扫描dao -->
	<context:component-scan base-package="cn.itcast_01_springmvc.dao"></context:component-scan>
	<!--指定扫描exception -->
	<context:component-scan base-package="cn.itcast_01_springmvc.exception"></context:component-scan>
	<!-- 视图解析器 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

	<!-- 匹配注解驱动,要使用spring mvc中的@Controller注解,就必需要配置<mvc:annotation-driven /> -->
	<!-- conversion-service注明了类型转换器 -->
	<mvc:annotation-driven conversion-service="myConversion" />
	<!-- 处理静态资源 -->
	<!-- 若是遇到mapping路径,就去找到location -->
	<mvc:resources location="/lib/" mapping="/lib/**" />

	<!-- 类型转换器 -->
	<bean id="myConversion"
		class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
		<property name="converters">
			<set>
				<bean class="cn.itcast_01_springmvc.converter.DateConverter"></bean>
			</set>
		</property>
	</bean>

	<!-- 配置拦截器 -->
	<mvc:interceptors>
		<!-- 配置多个拦截器 顺序执行 -->
		<mvc:interceptor>
			<!-- /* 是拦截全部的文件夹,不包含子文件夹 -->		
			<!-- /** 是拦截全部的文件夹及里面的子文件夹 -->
			<mvc:mapping path="/**" />
			<!-- 不拦截静态资源 -->
			<mvc:exclude-mapping path="/lib/**" />
			<bean class="cn.itcast_01_springmvc.interceptor.Myinterceptor1"></bean>
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<mvc:exclude-mapping path="/lib/**" />
			<bean class="cn.itcast_01_springmvc.interceptor.Myinterceptor2"></bean>
		</mvc:interceptor>
	</mvc:interceptors>

	<!-- SpringMVC文件上传 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!--defaultEncoding:请求的编码格式必须和用户JSP的编码一致,以便正确读取表单中的内容。 -->
		<property name="defaultEncoding" value="UTF-8" />
		<!-- maxUploadSize:设置文件上传大小上限(单位为字节) -->
		<property name="maxUploadSize" value="102400000" />
		<!--uploadTempDir:文件上传过程当中的临时目录,上传完成后,临时文件会自动删除-->
		<!--uploadTempDir能够不作设置,有默认的路径,上传完毕会临时文件会自动被清理掉 -->
		<property name="uploadTempDir" value="/upload/"></property>
	</bean>
</beans>

UserController.java再新增:

@RequestMapping(value = "/fileupload")
public String fileupload(String desc,MultipartFile file,Model model) throws IllegalStateException, IOException {
	System.out.println(desc);
	System.out.println(file);
	System.out.println(file.getOriginalFilename());
	if(file!=null&&file.getOriginalFilename()!=null&&file.getOriginalFilename().length()>0){
		String filepath="D:/Project resources/springMVC/";
		String origName=file.getOriginalFilename();
		//扩展名
		String extendsName=origName.substring(origName.lastIndexOf("."));
		//文件名
		String newFileName=UUID.randomUUID().toString()+extendsName;
		//文件
		File uploadFile=new File(filepath+newFileName);
		file.transferTo(uploadFile);
		model.addAttribute("filepath","/file/"+newFileName);
	}
	return "success";		
}

jsp的success.jsp页面以下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<img src="${filepath}"/>
</body>
</html>

万事俱备,只差上传表单:
add.jsp新增:

<h2>文件上传</h2>
<!-- 	能够经过配置Tomcat虚拟路径后能够经过 
http://localhost:8080/file/e861c7d3-473b-4cc3-8da1-41a7ef2f9d5d.jpg直接访问图片 -->
<form name="form3" action="fileupload" method="post"
		enctype="multipart/form-data">
	<input name="file" type="file"><br /> <input name="desc"
			type="text"><br />
	<button>上传</button>
</form>

http://localhost:8080/SpringMVC-02-Mvn/user上传图片并能再success页面预览