系列文章目录
文章目录
- Spring MVC
- Spring MVC 功能
- Spring MVC 实现原理
- 核⼼组件
- 组件之间运作流程
- Spring MVC 具体使⽤
- 流程梳理
- Spring MVC 常⽤注解 - @RequestMapping
- 参数绑定 - @RequestParam
- RESTful ⻛格的 URL 参数获取 - @PathVariable
- 映射 Cookie - @CookieValue
- 使⽤ POJO 绑定参数
- JSP ⻚⾯的转发和重定向
- 转发 - forward
- 重定向 - redirect
- Spring MVC 数据绑定
- 基本数据类型
- 包装类
- 数组
- List
- JSON
- FastJson
- Spring MVC 视图层解析
- 业务数据绑定到 request 域对象
- Map
- Model
- ModelAndView
- HttpServletRequest
- @ModelAttribute
- 业务数据绑定到 session 域对象
- HttpSession
- @SessionAttribute
- Spring MVC⾃定义数据类型转换器
- Spring MVC与RESTful的集成
- RESTful 特点:
- RESTful 具体来讲就是四种表现形式
- HiddenHttpMethodFilter 的实现原理
- Spring MVC实现⽂件的上传下载
- 单⽂件上传
- 多⽂件上传
- ⽂件下载
- Spring MVC 数据校验
- 基于 Validator 接⼝
- Annotation JSR-303 标准
- Spring MVC表单标签库
- 常⽤标签
- Spring MVC国际化
Spring MVC
Spring MVC 是 Spring Framework 提供的 Web 组件,全称是 Spring Web MVC,是⽬前主流的实现 MVC 设计模式的框架,提供前端路由映射、视图解析等功能
Spring MVC 功能
Spring MVC 实现原理
核⼼组件
- DispatcherServlet:前置控制器,负责调度其他组件的执⾏,可以降低不同组件之间的耦合性,是整个 Spring MVC 的核⼼模块
- Handler:处理器,完成具体的业务逻辑,相当于 Servlet
- HandlerMapping:DispatcherServlet 是通过 HandlerMapping 将请求映射到不同的 Handler
- HandlerInterceptor:处理器拦截器,是⼀个接⼝,如果我们需要进⾏⼀些拦截处理,可以通过实现该接⼝完成
- HandlerExecutionChain:处理器执⾏链,包括两部分内容:Handler 和 HandlerInterceptor(系统会有⼀个默认的 HandlerInterceptor,如果需要额外拦截处理,可以 添加拦截器进⾏设置)
- HandlerAdapter:处理器适配器,Handler 执⾏业务⽅法之前,需要进⾏⼀系列的操作包括表单的数据验证、数据类型的转换、将表单数据封装到 POJO 等,这⼀些列操作都是由
- HandlerAdapter 完成,DispatcherServlet 通过 HandlerAdapter 执⾏不同的 Handler
- ModelAndView:封装了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet
组件之间运作流程
Spring MVC 具体使⽤
1.创建Maven工程,选择maven-archetype-webapp,然后在pom.xml添加以下依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
2.main文件夹下创建java文件夹和resources文件夹,resources下配置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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- 配置⾃动扫描 package路径为java下的路径-->
<context:component-scan base-package="com.hqq"></context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 表示根目录/-->
<property name="prefix" value="/"></property>
<!-- 后缀 表示jsp文件-->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
3.在 web.xml 中配置 Spring MVC 的 DispatcherServlet
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定bean配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<!--所有请求都拦截-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4.添加controller包,添加MyHandler类
@Controller
public class MyHandler {
@RequestMapping("/index")
public String index(){
System.out.println("接收到请求");
//返回逻辑试图
return "index";
}
}
5.配置Tomcat(没有的先下载),在AddConfiguration里选择tomcat,配置Deployment如下
/:表示直接localhost:8080/index,就可以访问
如果是/test,则要localhost:8080/test/index,才可以访问
流程梳理
- 浏览器输入localhost:8080/index -> DispatcherServlet 接收到 URL 请求 index,结合 @RequestMapping("/index") 注解将该请求交给index()进⾏处理
- 执⾏ index() 业务⽅法,控制台打印⽇志,并且返回 "index" 字符串(逻辑视图)
- 结合 springmvc.xml 中的视图解析器配置,"index"加上前缀/,加上后缀.jsp ->找到⽬标资源:/index.jsp,即根⽬录下的 index.jsp ⽂件,将该 JSP 资源返回给客户端完成响应
Spring MVC 常⽤注解 - @RequestMapping
//----需要访问 localhost:8080/hello/index --------
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@RequestMapping("/index")
public String index(){
System.out.println("接收到了请求");
//返回逻辑视图
return "index";
}
}
- value:指定 URL 请求的实际地址,是 @RequestMapping 的默认值
@RequestMapping(value="/index") // = @RequestMapping("/index")
public String index(){
System.out.println("接收到了请求");
//返回逻辑视图
return "index";
}
- method:指定请求的 method 类型,包括 GET、POST、PUT、DELETE 等
@RequestMapping(value = "/index",method = RequestMethod.POST)
public String index(){
System.out.println("接收到了请求");
//返回逻辑视图
return "index";
}
通过postman 模拟POST请求,能够被访问到:
- params:指定 request 请求中必须包含的参数值,若不包含,⽆法调⽤该⽅法
@RequestMapping(value = "/index",params = {"id=1","name=tom"})
public String index(){
System.out.println("接收到了请求");
//返回逻辑视图
return "index";
}
参数绑定 - @RequestParam
- 1、在业务⽅法定义时声明参数列表
- 2、给参数列表添加 @RequestParam 注解进⾏绑定
@RequestMapping(value = "/index",method = RequestMethod.POST)
public String index(@RequestParam("num") Integer id,@RequestParam("str")
String name){
System.out.println("接收到了请求,参数是:id="+id+",name="+name);
//返回逻辑视图
return "index";
}
正确访问URL:localhost:8080/index?num=1&str=tom
错误访问URL :localhost:8080/index?id=1&name=tom
RESTful ⻛格的 URL 参数获取 - @PathVariable
- 传统的 URL:localhost:8080/hello/index?id=1&name=tom
- RESTful URL:localhost:8080/hello/index/1/tom
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name")
String name){
System.out.println(id+"-"+name);
return "index";
}
映射 Cookie - @CookieValue
@CookieValue("JSESSIONID")能够自动获取页面的jsessionid赋给形参
@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
使⽤ POJO 绑定参数
@Data
public class User {
private Integer id;
private String name;
//级联属性
private Address address;
}
Address类(POJO):
@Data
public class Address {
private Integer code;
private String value;
}
addUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/add" method="post">
<table>
<tr>
<td>编号:</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>姓名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>地址编号:</td>
<td><input type="text" name="address.code"/></td>
</tr>
<tr>
<td>地址信息:</td>
<td><input type="text" name="address.value"/></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
MyHandler
@RequestMapping(value="/add",method = RequestMethod.POST)
public String add(User user){
System.out.println(user);
return "index";
}
访问addUser.jsp页面:
提交之后,后台的User对象会获取到提交信息,根据addUser.jsp设定的属性对应赋值
JSP ⻚⾯的转发和重定向
转发 - forward
页面跳转的时候,浏览器显示的地址不变,默认
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name")
String name){
System.out.println(id+"-"+name);
return "forward:/index.jsp"; // = return "index";
}
重定向 - redirect
页面跳转的时候,浏览器显示的地址也跟着改变
因为不默认,所以 redirect:/ 必须写完整的jsp路径
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name")
String name){
System.out.println(id+"-"+name);
return "redirect:/index.jsp";
}
Spring MVC 数据绑定
- HTTP 请求传输的参数都是 String 类型的,Handler 业务⽅法中的参数是开发者指定的数据类型,int、 Integer、Object等,因此需要进⾏数据类型的转换
- Spring MVC 的 HandlerAdapter 组件会在执⾏ Handler 业务⽅法之前,完成参数的绑定,开发者直接使⽤即可
基本数据类型
@RequestMapping("/baseType")
@ResponseBody //添加这个就不会返回逻辑视图,而是将http请求参数赋给形参,后端输出
public String baseType(int id){
return "id:"+id;
}
包装类
@RequestMapping("/packageType")
@ResponseBody
public String packageType(Integer id){
return "id:"+id;
}
此时,id可以为null,但是id不可以是浮点类型或者字符串类型
@RequestMapping("/packageType")
@ResponseBody
public String packageType(@RequestParam(value = "id",required =
true,defaultValue = "0") Integer id){
return "id:"+id;
}
- value = "id":将 HTTP 请求中名为 id 的参数 与 ⽅法中的形参进⾏映射
- required:ture 表示 id 参数必填,false 表示⾮必填
- defaultValue = "0":表示当 HTTP 请求中没有 id 参数时,形参的默认值为 0
数组
@RequestMapping("/arrayType")
@ResponseBody
public String arrayType(String[] names){
StringBuffer stringBuffer = new StringBuffer();
for (String str:names){
stringBuffer.append(str).append(" ");
}
return "names:"+stringBuffer.toString();
}
List
@Data
public class UserList {
private List<User> users;
}
@RequestMapping("/listType")
@ResponseBody
public String listType(UserList users){
StringBuffer stringBuffer = new StringBuffer();
for(User user:users.getUsers()){
stringBuffer.append(user);
}
return "⽤户:"+stringBuffer.toString();
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html> <head>
<title>Title</title>
</head> <body>
<form action="/listType" method="post">
⽤户1ID:<input type="text" name="users[0].id"/><br/>
⽤户1姓名:<input type="text" name="users[0].name"/><br/>
⽤户2ID:<input type="text" name="users[1].id"/><br/>
⽤户2姓名:<input type="text" name="users[1].name"/><br/>
⽤户3ID:<input type="text" name="users[2].id"/><br/>
⽤户3姓名:<input type="text" name="users[2].name"/><br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
JSON
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
json.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type = "text/javascript" src = "js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
$(function(){
var user = {"id":1, "name":"张三"};
$.ajax({
url : "/jsonType",
data : JSON.stringify(user),
type : "POST",
contentType:"application/json;charset=UTF-8",
dataType:"JSON",
success:function (data) {
alert(data.id)
alert(data.name)
}
})
})
</script>
</head>
<body>
</body>
</html>
- JSON 数据必须⽤ JSON.stringify() ⽅法转换成字符串
- contentType:"application/json;charset=UTF-8" 不能省略
@RequestMapping("/jsonType")
@ResponseBody
public User jsonType(@RequestBody User user){
System.out.println(user);
return user;
}
- @RequestBody 注解
- @ResponseBody 注解
FastJson
<!--FastJson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.32</version>
</dependency>
2.sprimvc.xml
<mvc:annotation-driven>
<!-- 消息转换器 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8></property>
</bean>
<!-- fastjson -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
</mvc:message-converters>
</mvc:annotation-driven>
Spring MVC 视图层解析
- page
- request
- session
- application
- Map
- Model
- ModelAndView
- @SessionAttribute
- @ModelAttribute
- Servlet API
业务数据绑定到 request 域对象
Map
@RequestMapping("/map")
public String map(Map<String,Object> map){
User user = new User();
user.setId(1);
user.setName("张三");
map.put("user",user);
return "show";
}
2.show.jsp
<%--
Created by IntelliJ IDEA.
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--不加上这个,会打印"${requestScope.user}"-->
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${requestScope.user}
</body>
</html>
3.结果
Model
@RequestMapping("/model")
public String model(Model model){
User user = new User();
user.setId(1);
user.setName("张三");
model.addAttribute("user",user);
return "show";
}
ModelAndView
不同点是:返回值为ModelAndView类型,
- 填充业务数据
- 绑定视图信息
@RequestMapping("/mav")
public ModelAndView modelAndView(){
ModelAndView modelAndView = new ModelAndView();
User user = new User();
user.setId(1);
user.setName("张三");
//填充业务数据
modelAndView.addObject("user",user);
//绑定视图信息
modelAndView.setViewName("show");
return modelAndView;
}
HttpServletRequest
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
@RequestMapping("/request")
public String request(HttpServletRequest request){
User user = new User();
user.setId(1);
user.setName("张三");
request.setAttribute("user",user);
return "show";
}
@ModelAttribute
- 定义⼀个⽅法,该⽅法⽤来放好要填充到业务数据中的对象
- 给该⽅法添加 @ModelAttribute 注解
@RequestMapping("/modelAttribute")
public String modelAttribute(){
return "show";
}
@ModelAttribute
public User getUser(){
User user = new User();
user.setId(1);
user.setName("张三");
return user;
}
@ModelAttribute
public void getUser(Model model){
User user = new User();
user.setId(1);
user.setName("张三");
model.addAttribute("user",user);
}
业务数据绑定到 session 域对象
HttpSession
@RequestMapping("/session")
public String session(HttpSession session){
User user = new User();
user.setId(1);
user.setName("张三");
session.setAttribute("user",user);
return "show";
}
JSP
<%--
Created by IntelliJ IDEA.
User: Administrator
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--不加上这个,会打印"${requestScope.user}"-->
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--requestScope变为sessionScope-->
${sessionScope.user}
</body>
</html>
@SessionAttribute
@SessionAttributes(value = "user")
public class ViewHandler{
....................
}
@Controller
@SessionAttributes(types=User.class)
public class ViewHandler {
...
}
@Controller
@SessionAttributes(types={User.class,Address.class})
public class ViewHandler {
...
}
只要业务方法中的request装载有User或者Address的数据,那么对应的也会给session装载上
Spring MVC⾃定义数据类型转换器
public class DateConverter implements Converter<String, Date> {
private String pattern;
public DateConverter(String pattern){
this.pattern = pattern;
}
@Override
public Date convert(String s) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.pattern);
try {
return simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.hqq.converter.DateConverter">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd">
</constructor-arg>
</bean>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
3.date.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/converter/date" method="post">
<input type="text" name="date"/>
<input type="submit" value="提交">
</form>
</body>
</html>
4.Handler
@Controller
@RequestMapping("/converter")
public class ConverterHandler {
@RequestMapping("/date")
@ResponseBody
public String date(Date date){
return date.toString();
}
}
运行步骤:
- tomcat启动时,IOC容器会根据springmvc.xml配置的bean创建一个DateConverter对象
- 在date.jsp页面输入日期字符串的时候,由DateConverter转为date类型,提交给Handler业务方法的入参
- Handler将date类型数据转为String类型在视图层localhost:8080/converter/date显示日期
Spring MVC与RESTful的集成
- Resources
- Pepresentation
- State Transfer
RESTful 特点:
RESTful 具体来讲就是四种表现形式
- GET ⽤来获取资源---------查
- POST ⽤来创建资源-------增
- PUT ⽤来修改资源---------改
- DELETE ⽤来删除资源---删
两个终端要完成数据交互,基于 RESTful 的⽅式,增删改查操作分别需要使⽤不同的 HTTP 请求类型来访问
传统的 Web 开发中,from 只⽀持 GET 和 POST,不⽀持 DELETE 和 PUT,如何解决?通过添加HiddenHttpMethodFilter 过滤器,可以将 POST 请求转为 PUT 或者 DELETE
HiddenHttpMethodFilter 的实现原理
实现
1.在form表单中添加隐藏于标签,name为_method,value为DELETE/PUT
<html>
<head><title>Title</title></head>
<body>
<form action="/rest/update" method="post"> <!--本来请求是POST-->
<%--用_method,转为PUT请求--%>
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
<!-- HiddenHttpMethodFilter -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filterclass>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.Handler
@PutMapping("/update")
@ResponseBody
public String update(HttpServletResponse response){
//添加可以避免输出中文乱码
response.setCharacterEncoding("UTF-8");
return "已接收到PUT请求";
}
- 添加课程,成功则返回全部课程信息
- 查询课程,通过 id 查询对应课程信息
- 修改课程,成功则返回修改之后的全部课程信息
- 删除课程,成功则返回删除之后的全部课程信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/course/add" method="post">
<table>
<tr>
<td>课程编号:</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>课程名称:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>课程价格:</td>
<td><input type="text" name="price"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html> <head>
<title>Title</title>
</head> <body>
<form action="/course/update" method="post">
<input type="hidden" name="_method" value="PUT"/>
<table>
<tr>
<td>编号:</td>
<td>
<input type="text" name="id" readonly value="${courser.id}"/>
</td>
</tr>
<tr>
<td>名称:</td>
<td>
<input type="text" name="name" value="${courser.name}"/>
</td>
</tr>
<tr>
<td>价格:</td>
<td>
<input type="text" name="price" value="${courser.price}"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="修改"/>
</td>
</tr>
</table>
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page isELIgnored="false" %>
<html>
<body>
<h2>Hello World!</h2>
<table>
<tr>
<th>编号</th>
<th>名称</th>
<th>价格</th>
<th>操作</th>
</tr>
<!--modelAndView对象装载的key叫list-->
<c:forEach items="${list}" var="course">
<tr>
<td>${course.id}</td>
<td>${course.name}</td>
<td>${course.price}</td>
<td>
<form action="/course/deleteById/${course.id}" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删除">
</form>
<a href="/course/findById/${course.id}">修改</a>
</td>
</tr>
</c:forEach>
<tr>
<td>
<form action="/addCource.jsp" method="post">
<input type="submit" value="添加">
</form>
</td>
</tr>
</table>
</body>
</html>
注:使用c:forEach要添加jstl包,在pom.xml添加以下依赖
<!--JSTL-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
乱码解决方法:在springmvc.xml中把中文乱码过滤器放在最上
<!--SpringMVC 中文乱码-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- HiddenHttpMethodFilter -->
<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>
2.实体类Course
@Repository
public class CourseRepository {
private Map<Integer, Course> courseMap;
public CourseRepository(){
courseMap = new HashMap<>();
courseMap.put(1,new Course(1,"Java基础",35.0));
courseMap.put(2,new Course(2,"Java高级",45.0));
courseMap.put(3,new Course(3,"企业级框架",55.0));
}
public Collection<Course> findAll(){
return courseMap.values();
}
public Course findById(Integer id){
return courseMap.get(id);
}
public void saveOrUpdate(Course course){
courseMap.put(course.getId(),course);
}
public void deleteById(Integer id){
courseMap.remove(id);
}
@Repository
public class CourseRepository {
private Map<Integer, Course> courseMap;
public CourseRepository(){
courseMap = new HashMap<>();
courseMap.put(1,new Course(1,"Java基础",35.0));
courseMap.put(2,new Course(2,"Java高级",45.0));
courseMap.put(3,new Course(3,"企业级框架",55.0));
}
public Collection<Course> findAll(){
return courseMap.values();
}
public Course findById(Integer id){
return courseMap.get(id);
}
public void saveOrUpdate(Course course){
courseMap.put(course.getId(),course);
}
public void deleteById(Integer id){
courseMap.remove(id);
}
}
@Controller
@RequestMapping("/course")
public class CourseController {
@Autowired
private CourseRepository courseRepository;
@PostMapping("/add")
public String add(Course course){
courseRepository.saveOrUpdate(course);
return "redirect:/course/findAll";
}
@GetMapping("/findAll")
public ModelAndView findAll(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("list",courseRepository.findAll());
return modelAndView;
}
@DeleteMapping("/deleteById/{id}")
public String deleteById(@PathVariable("id") Integer id){
courseRepository.deleteById(id);
return "redirect:/course/findAll";
}
@GetMapping("findById/{id}")
public ModelAndView findById(@PathVariable("id") Integer id){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("edit");
modelAndView.addObject("courser",courseRepository.findById(id));
return modelAndView;
}
@PutMapping("/update")
public String update(Course course){
courseRepository.saveOrUpdate(course);
return "redirect:/course/findAll";
}
}
Spring MVC实现⽂件的上传下载
单⽂件上传
<!--文件上传-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2. JSP ⻚⾯
- input 的 type 设置为 fifile
- form 表单的 method 设置为 post
- form 表单的 enctype 设置为 multipart/form-data
demo:做一个上传图片,然后展示此图片的网页
upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="img"/>
<input type="submit" value="提交">
</form>
<img src="${src}">
</body>
</html>
uploadHandler
@Controller
@RequestMapping("/file")
public class upLoadHandler {
@PostMapping("/upload")
public String upload(@RequestParam("img")MultipartFile img, HttpServletRequest request){
if(img.getSize()>0){
//1.path = apache-tomcat-9.0.63/webapps/ROOT/file 2.getRealPath("file")表示/ROOT/下的file文件夹
String path = request.getSession().getServletContext().getRealPath("file");
String fileName = img.getOriginalFilename();
//将path下的名字为fileName的文件变为对象
File file = new File(path,fileName);
try {
//上传文件到服务器
img.transferTo(file);
request.setAttribute("src","/file/"+fileName); //”/file/“ = ”ROOT/file/"
} catch (IOException e) {
e.printStackTrace();
}
}
return "upload";
}
}
配置图片静态资源访问-web.xml
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
配置multipartResolverbean-springmvc.xml
<bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
多⽂件上传
uploads.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/uploads" method="post" enctype="multipart/form-data">
file1:<input type="file" name="imgs"/><br>
file2:<input type="file" name="imgs"/><br>
file3:<input type="file" name="imgs"/><br>
<input type="submit" value="提交">
</form>
<c:forEach items="${list}" var="path">
<img src="${path}" width="300px">
</c:forEach>
</body>
</html>
Handler
@PostMapping("uploads")
public String uploads(@RequestParam("imgs")MultipartFile[] imgs,HttpServletRequest request){
//存放文件路径
List<String> pathList = new ArrayList<>();
for (MultipartFile img:imgs) {
if(img.getSize()>0){
String path =request.getSession().getServletContext().getRealPath("file");
String fileName = img.getOriginalFilename();
File file = new File(path,fileName);
try {
img.transferTo(file);
pathList.add("/file/"+fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//request保存文件路径,直接src指定路径,显示图片
request.setAttribute("list",pathList);
return "uploads";
⽂件下载
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html> <head>
<title>Title</title>
</head> <body>
<a href="/file/download?fileName=1.png">1.png</a><br/>
<a href="/file/download?fileName=2.png">2.png</a><br/>
<a href="/file/download?fileName=3.png">3.png</a>
</body>
</html>
2.Handler
@GetMapping("/download")
public void download(String fileName, HttpServletRequest request, HttpServletResponse response){
if (fileName!=null){
String path =request.getSession().getServletContext().getRealPath("file");
File file = new File(path,fileName);
OutputStream outputStream =null;
if (file.exists()){
//设置下载文件
response.setContentType("application/force-download");
//设置文件名
response.setHeader("Content-Disposition","attachment;filename="+fileName);
try {
outputStream = response.getOutputStream();
outputStream.write(FileUtils.readFileToByteArray(file));
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(outputStream!=null){
try{
//关流
outputStream.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
}
Spring MVC 数据校验
- 基于 Validator 接⼝进⾏校验
- 使⽤ Annotation JSR-303 标准校验
基于 Validator 接⼝
1.创建Student实体类
@Data
public class Student {
private String name;
private String password;
}
public class StudentValidation implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return clazz.equals(Student.class);
}
@Override
public void validate(Object target, Errors errors) {
//rejectIfEmpty(error表示会报错,”name“表示name属性,null表示如果值是null的时候,默认报错信息是”姓名不能为空“)
ValidationUtils.rejectIfEmpty(errors,"name",null,"(提示:姓名不能为空)");
ValidationUtils.rejectIfEmpty(errors,"password",null,"(提示:密码不能为空)");
}
}
3.login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!--引入表单标签库-->
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>学生登陆</title>
</head>
<body>
<h1>登陆系统</h1>
<!--modelAttribute指定了在Handler业务方法中添加了需要校验的对象-->
<form:form modelAttribute="student" action="/validate/login" method="post">
<tr>学生姓名:<form:input path="name"></form:input><form:errors path="name"></form:errors></tr>
学生密码:<form:input path="password"></form:input><form:errors path="password"></form:errors>
<tr><input type="submit" value="提交"></tr>
</form:form>
</body>
</html>
4、控制层业务⽅法
必须通过/validate/login 去访问,因为login()方法会通过model传一个student对象才能启动校验规则,直接访问login.jsp会报错
@Controller
@RequestMapping("/validate")
public class ValidateHandler {
//给JSP表单绑定模型对象,绑定才能启用校验
@GetMapping("/login")
public String login(Model model){
model.addAttribute(new Student());
return "login";
}
//数据校验
@PostMapping("login")
public String login(@Validated Student student, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return "login";
}
return "success";
}
}
5、springmvc.xml 配置 validator
<bean id="studentValidator" class="com.hqq.validation.StudentValidation"></bean>
<!--指定bean id-->
<mvc:annotation-driven validator="studentValidator"></mvc:annotation-driven>
6.结果:
Annotation JSR-303 标准
- @Null 只能为 null
- @NotNull 不能为 null
- @Size 设置数据⻓度
- @NotEmpty 不能为空
- String str = null;
- String str = "";
1.在pom.xml上添加依赖
<!--JSR 303 JSR是Java Specification Requests的缩写,意思是Java 规范提案-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.6.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.4.1.Final</version>
</dependency>
<!-- JDK9以上 另外要添加以下依赖 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
2.创建Account实体类,并用注解的方式指定校验规则
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* @Author 苦恼的java小宝
* @Date 2022/6/13 18:00
* @ClassName: Account
* @Version 1.0
*/
@Data
public class Account {
@NotEmpty(message = "用户名不能为空")
private String username;
@Size(min = 6,max = 20,message = "密码长度为6-20位")
private String password;
@Email(regexp = "\"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\\\\\\\\\\\\\\\.[a-zA-Z0-9-\n" +
"]+)*\\\\\\\\\\\\\\\\.[a-zA-Z0-9]{2,6}$",message ="请输入正确的邮箱" )
private String email;
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\\\\\\\\\\\\\\\d{8}$",message = "请输入正确的手机号")
private String phone;
}
3.Handler
@GetMapping("/register")
public String register(Model model){
model.addAttribute(new Account());
return "register";
}
@PostMapping("/register")
public String register(@Valid Account account,BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "regiser";
}
return "success";
}
4、register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>⽤户注册</h1>
<form:form modelAttribute="account" action="/validate/register" method="post">
⽤户名:<form:input path="username"></form:input><form:errors path="username"></form:errors><br/>
密码:<form:input path="password"></form:input><form:errors path="password"></form:errors><br/>
邮箱:<form:input path="email"></form:input><form:errors path="email"></form:errors><br/>
电话:<form:input path="phone"></form:input><form:errors path="phone"></form:errors><br/>
<input type="submit" value="提交"/>
</form:form>
</body>
</html>
Spring MVC表单标签库
demo:通过jsp修改student的信息
1.Student实体类
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender; }
2.Handler
@Controller
@RequestMapping("/student")
public class StudentHandler {
@RequestMapping("/get")
public String get(Model model){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(22);
student.setGender("男");
model.addAttribute("student",student);
return "student";
}
}
3.student.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>修改学⽣信息</h1>
<%--不用表单标签库的情况--%>
<form action="" method="post">
学⽣编号:<input type="text" name="id" value="${student.id}" readonly/><br/>
学⽣姓名:<input type="text" name="name" value="${student.name}"/><br/>
学⽣年龄:<input type="text" name="age" value="${student.age}"/><br/>
学⽣性别:<input type="text" name="gender" value="${student.gender}"/><br/>
<input type="submit" value="提交"/>
</form>
<%--使用表单标签库的情况--%>
<%--功能一样,代码简单--%>
<form:form modelAttribute="student" action="/student/update" method="post">
学⽣编号:<form:input path="id"></form:input><br/>
学⽣姓名:<form:input path="name"></form:input><br/>
学⽣年龄:<form:input path="age"></form:input><br/>
学⽣性别:<form:input path="gender"></form:input><br/>
<input type="submit" value="提交"/>
</form:form>
</body>
</html>
常⽤标签
<!--渲染的是 HTML 中的 <form></form> ,通过 modelAttribute 属性绑定具体的业务数据-->
<form:form modelAttribute="student" method="post"></form:form>
2、input 标签
渲染的是 HTML 中的 <input type="text"/> ,from 标签绑定的是业务数据,input 标签绑定的是业 务数据中的属性值,通过 path 与业务数据的属性名对应,并⽀持级联
<form:input path="name"></form:input>
3、password 标签
<form:password path="password"></form:password>
4、checkbox 标签
渲染的是 HTML 中的 <input type="checkbox"/> ,通过 path 与业务数据的属性名对应,可以绑定 boolean、数组和集合
<form:checkbox path="hobby" value="读书"></form:checkbox>
<form:checkboxs items="${student.hobby}" path="selectHobby"></form:checkboxs>
student.setRadioId(1);
<form:radiobutton path="radioId" value="0"></form:radiobutton>男
<form:radiobutton path="radioId" value="1"></form:radiobutton>⼥
Spring MVC国际化
<!-- 国际化资源⽂件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSour
ce">
<!-- 多语⾔配置⽂件放在根路径,以 language 开头 -->
<property name="basename" value="classpath:language"></property>
<property name="useCodeAsDefaultMessage" value="true"></property>
</bean>
<!-- 拦截器 -->
<mvc:interceptors>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"></property>
</bean>
</mvc:interceptors>
<!-- 配置 SessionLocaleResolver,动态获取 Locale 对象,存⼊ Session -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
language.cn = \u4E2D\u6587
language.en = English
info = login
username = username
password = password
repassword = repassword
tel = tel
email = email
submit = submit
reset = reset
language.cn = \u4E2D\u6587
language.en = English
info = \u767B\u9646
username = \u7528\u6237\u540D
password = \u5BC6\u7801
repassword = \u786E\u8BA4\u5BC6\u7801
tel = \u7535\u8BDD
email = \u7535\u5B50\u90AE\u7BB1
submit = \u63D0\u4EA4
reset = \u91CD\u7F6E
@Controller
@RequestMapping("/inter")
public class InterHandler {
@GetMapping("/index")
public String index(){
return "inter";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="index?lang=en_US">English</a>
<a href="index?lang=zh_CN">中⽂</a>
<h1><spring:message code="info"></spring:message></h1>
<form>
<spring:message code="username"/>:<input type="text"/><br/>
<spring:message code="password"/>:<input type="password"/><br/>
<spring:message code="repassword"/>:<input type="password"/><br/>
<spring:message code="tel"/>:<input type="text"/><br/>
<spring:message code="email"/>:<input type="text"/><br/>
<input type="submit" value="<spring:message code="submit"/> "/>
<input type="reset" value="<spring:message code="reset"/> "/>
</form>
</body>
</html>
5、结果
总结
开始myBatis