SpringMVC是Spring Framework提供的Web组件,全称是Spring Web MVC,是目前主流的实现MVC设计模式的框架,提供前端路由映射、视图解析等功能。
MVC:Controller(控制层),Model(模型层),View(视图层)
流程:Controller接收客户端请求,调用相关业务层组件产出Model,或业务数据并返回给Controller,Controller再结合View完成业务数据的视图层渲染,并将结果响应给客户端。
Spring MVC对这套MVC流程进行封装,帮助开发者屏蔽底层代码,并且开放相关接口供开发者调用,让MVC开发变得更加简单方便。
核心组件
| 组件 | 作用 |
| DispatcherServlet | 前置控制器,负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块 |
| Handler | 处理器,完成具体的业务逻辑,相当于Servlet |
| HandlerMapping | DispatcherServlet是通过HandlerMapping将请求映射到不同的Handler |
| HandlerInterceptor | 处理器拦截器,是一个接口,如果需要进行一些拦截处理,可以通过该接口完成 |
| HandlerExecutionChain | 处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器进行设置) |
| HandlerAdapter | 处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型的转换、将表单封装到POJO等 |
| ModelAndView | 封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet |
| ViewResolver | 视图解析器,DispatcherServlet通过它将逻辑视图解析为物理视图,最终将渲染的结果响应给客户端 |
工作流程
一个简单的例子:
添加一个Maven工程,导入pom依赖
org.springframework
spring-webmvc
{版本号}
在web.xml中配置SpringMVC的DispatcherServlet
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc.xml
springmvc
/
配置springmvc.xml
创建Handler
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloHandler {
@RequestMapping("/index")
public String index(){
System.out.println("接收到了请求");
//返回逻辑视图
return "index";
}
}
流程梳理
@RequestMapping
Spring MVC通过@RequestMapping注解将URL请求与业务方法进行映射,在控制器的类定义处以及方法定义处都可以添加@RequestMapping,在类定义处添加相当于多了一层访问路径。
如上例,在类定义处加上该注解有
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@RequestMapping("/index")
public String index(){
System.out.println("接收到了请求");
//返回逻辑视图
return "index";
}
}
则访问地址变为:http://localhost:8080/hello/index
@RequestMapping常用参数
| 参数 | 用法 |
| value | 指定URL请求的实际地址,是@RequestMapptin的默认值,只有一个参数时可以省略,两个或以上参数时必须写 |
| method | 指定请求的method类型,包括GET、POST、PUT、DELETE等 |
| params | 指定request请求中必须包含的参数值,若不包含,无法调用该方法 params同时指定多个参数则写成params={"key1=value1","key2=value2"}的形式 该形式代码表名请求中必须包含key1和key2两个参数,并且值必须为其对应的值,否则抛出400错误 |
params是对URL请求参数进行限制,不满足条件的URL无法访问该方法,需要在业务方法中获取URL的参数值
例:将controller改为post方法,且传递参数num和str
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class HelloHandler {
@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?id=1&name=tom
RESTful URL:localhost:8080/hello/index/1/tom
修改controller
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
System.out.println(id+"-"+name);
return "index";
}
将参数列表的注解改为@PathVariable即可实现。
@RequestMapping("/cookie")
public String getCookie(@RequestParam(required = false)@CookieValue("JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
Spring MVC会根据请求参数名和POJO属性名进行匹配,自动为该对象填充属性值,并支持级联
创建实体类User
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
}
新建一个addUser.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
在controller类中添加
@RequestMapping(value = "/add",method = RequestMethod.POST)
public String add(User user){
System.out.println(user);
return "index";
}
即可实现数值接收
如果出现中文乱码问题可以通过配置过滤器来解决,在web.xml中添加:
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
encodingFilter
/*
再加一套User里面的实体类Address,User变为
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private Address address;
}
Address类
import lombok.Data;
@Data
public class Address {
private Integer code;
private String value;
}
addUser.jsp添加地址信息
Title
框架可以根据变量名找到实体类中的变量自动进行绑定
主体对象可以没有无参构造函数,但是级联对象必须有无参构造函数
Spring MVC默认以转发的形式响应JSP,可以手动进行修改。
以上述RESTful例为例,重定向访问
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
System.out.println(id+"-"+name);
return "redirect:/index.jsp";
}
注:设置重定向的时候不能写逻辑视图,必须写明资源的物理路径,如"redirect:/index.jsp"
转发的写法:
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
System.out.println(id+"-"+name);
return "forward:/index.jsp";
}
等同于
@RequestMapping("/restful/{id}/{name}")
public String restful(@PathVariable("id") Integer id,@PathVariable("name") String name){
System.out.println(id+"-"+name);
return "index";
}
数据绑定:在后台业务方法中,直接获取前端HTTP请求中的参数
HTTP请求传输的参数都是String类型的,Handler业务方法中参数是开发者指定的数据类型,int、Integer、Object,因此需要进行数据类型的转换。
Spring MVC的Handler Adapter组件会在执行Handler业务方法之前,完成参数的绑定,开发者可以直接使用。
例:在Controller添加
@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id)
{
return "id:"+id;
}
@ResponseBody会直接返回id的字符串。
客户端HTTP请求中必须包含id参数,否则抛出500异常,因为id不能为null。同时id的值必须为数值且必须为整数,否则抛出400异常。
@RequestMapping("/packageType")
@ResponseBody
public String packageType(Integer id){
return "id:"+id;
}
如果HTTP请求中没有包含id参数,不会报错,id的值就是null,会直接返回id:null给客户端。但是如果id=a或者id=1.5同样会抛出400异常,因为数据类型无法匹配。
可以给参数列表添加@RequestParam注解,可以对参数进行相关设置
@RequestMapping("/packageType")
@ResponseBody
public String packageType(@RequestParam(value = "id",required = true,defaultValue = "0") Integer id){
return "id:"+id;
}
| value="id" | 将HTTP请求中名为id的参数与Handler业务方法中的形参进行映射 |
| required | true表示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();
}
为了使返回值不出现乱码,所以在springmvc.xml中加入
Spring MVC不支持List类型的直接转换,需要包装成Object。
List自定义包装类
类UserList
import lombok.Data;
import java.util.List;
@Data
public class UserList {
private List users;
}
addList.jsp
Title
Controller类
@RequestMapping(value = "/listType",method = RequestMethod.POST)
@ResponseBody
public String listType(UserList users){
StringBuffer stringBuffer=new StringBuffer();
for(User user:users.getUsers())
{
stringBuffer.append(user);
}
return "users:"+users.toString();
}
User类与前例一致,需要注意的是User类一定要有无参构造器,否则报错
在pom.xml中添加依赖
com.alibaba
fastjson
1.2.79
在springmvc.xml中配置
在web.xml文件中添加读取js文件的标签
default
*.js
导入jQuery.min.js文件
创建json.jsp
Title
则数据从页面传入后端再由后端返回给页面
业务方法
@RequestMapping("/jsonType")
@ResponseBody
public User jsonType(@RequestBody User user){
user.setId(2);
return user;
}
@RequestBody注解
读取HTTP请求参数,通过SpringMVC提供的HttpMessageConverter接口读取的参数转为JSON、XML格式的数据,绑定到业务方法的形参。
@ResponseBody注解
将业务方法返回的对象,通过HttpMessageConverter接口转为指定格式的数据,JSON、XML等,响应给客户端。
需要使用组件结合@RequestBody注解将JSON转换为Java Bean,这里使用FastJson,其优势是如果属性为空就不会将其转为JSON
调用Web资源给域对象传值
page
request
session
application
业务数据的绑定是指将业务数据绑定给JSP域对象,业务数据的绑定是由ViewResolver来完成,开发时,先添加业务数据,再交给ViewResolver来绑定。Spring MVC提供了以下几种方式来添加业务数据:
Spring MVC在调用业务方法之前会创建一个隐含对象作为业务数据的存储容器,设置业务方法的入参为Map类型,Spring MVC会将隐含对象的引用传递给入参。
创建一个Controller类ViewHandler
import com.test.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
@Controller
@RequestMapping("/view")
public class ViewHandler {
@RequestMapping("/map")
public String map(Map map){
User user=new User();
user.setId(1);
user.setName("张三");
map.put("user",user);
return "show";
}
}
创建一个show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
Title
${requestScope.user}
Model与Map类似,业务方法通过入参来完成业务数据的绑定
Controller类写入
@RequestMapping("/model")
public String model(Model model)
{
User user=new User();
user.setId(1);
user.setName("张三");
model.addAttribute("user",user);
return "show";
}
与Map或者Model不同的是,ModelAndView不但包含业务数据,同时也封装了视图信息,如果使用ModelAndView来处理业务数据,业务方法的返回值必须是ModelAndView对象
业务方法中对ModelAndView进行两个操作:
方法一
public ModelAndView modelAndView1()
{
ModelAndView modelAndView=new ModelAndView();
User user=new User();
user.setId(1);
user.setName("张三");
//填充业务数据
modelAndView.addObject("user",user);
//绑定视图信息
modelAndView.setViewName("show");
return modelAndView;
}
方法二
@RequestMapping("/mav2")
public ModelAndView modelAndView2(){
ModelAndView modelAndView=new ModelAndView();
User user=new User();
user.setId(1);
user.setName("张三");
modelAndView.addObject("user",user);
View view=new InternalResourceView("/show.jsp");
modelAndView.setView(view);
return modelAndView;
}
方法三
@RequestMapping("/mav3")
public ModelAndView modelAndView3()
{
ModelAndView modelAndView=new ModelAndView("show");
User user=new User();
user.setId(1);
user.setName("张三");
modelAndView.addObject("user",user);
return modelAndView;
}
方法四
@RequestMapping("/mav4")
public ModelAndView modelAndView4()
{
View view=new InternalResourceView("/show.jsp");
ModelAndView modelAndView=new ModelAndView(view);
User user=new User();
user.setId(1);
user.setName("张三");
modelAndView.addObject("user",user);
return modelAndView;
}
方法五
@RequestMapping("/mav5")
public ModelAndView modelAndView5(){
Map map=new HashMap<>();
User user=new User();
user.setId(1);
user.setName("张三");
map.put("user",user);
ModelAndView modelAndView=new ModelAndView("show",map);
return modelAndView;
}
方法六
@RequestMapping("/mav6")
public ModelAndView modelAndView6()
{
Map map=new HashMap<>();
User user=new User();
user.setId(1);
user.setName("张三");
map.put("user",user);
View view=new InternalResourceView("/show.jsp");
ModelAndView modelAndView=new ModelAndView(view,map);
return modelAndView;
}
方法七
@RequestMapping("/mav7")
public ModelAndView modelAndView7(){
User user=new User();
user.setId(1);
user.setName("张三");
ModelAndView modelAndView=new ModelAndView("show","user",user);
return modelAndView;
}
方法八
@RequestMapping("/mav8")
public ModelAndView modelAndView8(){
User user=new User();
user.setId(1);
user.setName("张三");
View view=new InternalResourceView("/show.jsp");
ModelAndView modelAndView=new ModelAndView(view,"user",user);
return modelAndView;
}
Spring MVC可以在业务方法中直接获取Servlet原生Web资源,只需要在方法定义时添加HttpServletRequest入参即可,在方法体中直接使用request对象
添加pom.xml参数导入servlet
javax.servlet
servlet-api
2.5
controller
@RequestMapping("/request")
public String request(HttpServletRequest httpServletRequest){
User user=new User();
user.setId(1);
user.setName("张三");
httpServletRequest.setAttribute("user",user);
return "show";
}
Spring MVC还可以通过@ModelAttribute注解的方式添加业务数据:
@RequestMapping("/modellAttribute")
public String modelAttribute(){
return "show";
}
@ModelAttribute
public User getUser(){
User user=new User();
user.setId(1);
user.setName("张三");
return user;
}
@ModelAttribute注解的作用是当Handler接收到一个请求后,无论调用哪个业务方法都会优先调用被@ModelAttribute注解修饰的方法,并将其返回值作为业务数据,再进入到业务方法中,此时业务方法只需要返回视图信息即可,不需要返回业务数据,即使返回业务数据,也会被@ModelAttribute注解修饰的方法返回的数据所覆盖
域对象中存值都以key-value形式存储的,那么此时key值默认值是物业数据对应的类的类名首字母小写之后的结果。
如果getUser没有返回值则必须手动在该方法中填充业务数据,使用Map或Model均可
public void getUser(Model model)
{
User user=new User();
user.setId(1);
user.setName("张三");
model.addAttribute("user",user);
}
如果同时存在两个@ModelAttribute注解方法,直接给Model进行装载的方法优先级更高。
通过session传递
@RequestMapping("/session")
public String session(HttpSession session){
User user=new User();
user.setId(1);
user.setName("张三");
session.setAttribute("user",user);
return "show";
}
将作用域改为sessionScope
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
Title
${sessionScope.user}
@SessionAttribute
@SessionAttribute注解不是给方法添加的,而是给类添加的。
@Controller
@RequestMapping("/view")
@SessionAttributes("user")
public class ViewHandler {
@RequestMapping("/sessionAnnotation")
public ModelAndView sessionAnnotation(){
ModelAndView modelAndView=new ModelAndView("show");
User user=new User();
user.setId(1);
user.setName("张三");
modelAndView.addObject("user",user);
return modelAndView;
}
}
@SessionAttributes通过key值定位,多个key值时可以写作:
@SessionAttributes(value={"user","student"})
@SessionAttributes也可以通过对象名添加
@SessionAttributes(types=User.class)
或
@SessionAttributes(type={User.class,Address.class})
只要给类加了@SessionAttributes注解之后,无论类中的哪个业务方法被访问,将业务数据绑定到request域对象的同时,也会将业务数据绑定到session域对象中,也就是说request和session对象会同时存在业务数据,前提是request域中的key值需要和@SessionAttributes注解中的value值一致。
import org.springframework.core.convert.converter.Converter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter {
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 (Exception e){e.printStackTrace();}
return null;
}
}
在springmvc.xml中配置conversionService bean,这个bean是org.springframework.context.support.ConversionServiceFactoryBean的实例化对象,同时bean中必须包含一个converters属性,在其中注册所有需要使用的自定义转换器
添加一个Student类进行转换
Student类
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
}
springmvc.xml添加
添加转换类StudentConverter
import com.test.entity.Student;
import org.springframework.core.convert.converter.Converter;
public class StudentConverter implements Converter {
@Override
public Student convert(String s) {
String[] args=s.split("-");
Student student=new Student();
student.setId(Integer.parseInt(args[0]));
student.setName(args[1]);
student.setAge(Integer.parseInt(args[2]));
return student;
}
}
添加jsp页面student.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
注册controller
import com.test.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping(value = "/converter")
public class ConvertHandler {
@RequestMapping("/student")
@ResponseBody
public Student student(Student student, HttpServletResponse response)
{
response.setCharacterEncoding("UTF-8");
return student;
}
}
RESTful的优点:结构清晰、有统一的标准、拓展性好
资源指的是网络中的某个具体文件,类型不限,可以是文本、图片、视频、音频、数据流等,是网络中真实存在的实体。可以通过统一资源定位符找到这个实体,URI,每个资源都有一个特定的URI,通过URI就可以找到一个具体的资源。
资源表现层,资源的具体表现形式,例如一段文字,可以使用TXT、HTML、XML、JSON等不同的形式来描述它。
状态转化是指客户端和服务端之间的数据交互,因为HTTP请求不能传输数据的状态,所有的状态都保存在服务端,如果客户端希望访问服务端的数据,就需要使其发生状态改变,同时这种状态转化是建立在表现层上的,完成转换就表示资源的表现形式发生了改变。
RESTful概念比较抽象,特点有两个:
具体来讲就是四种表现形式,HTTP协议中四种请求类型(GET、POST、PUT、DELETE)分别表示四种常规操作,CRUD
两个终端要完成数据交互,基于RESTful的方式,增删改查操作分别需要使用不同的HTTP请求类型来访问。
传统的Web开发中,form只支持GET和POST,不支持DELETE和PUT,通过添加HiddenHttpMethodFilter过滤器,可以将POST请求转为PUT或DELETE。
HiddenHttpMethodFilter检测请求参数中是否包含_method参数,如果包含则取出它的值,并且判断请求类型之后完成请求类型的转换,然后继续传递。
实现步骤
在form表单中添加隐藏域标签,name为_method,value为DELETE或PUT
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
在web.xml中配置HiddenHttpMethodFilter
HiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
HiddenHttpMethodFilter
/*
Handler
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/rest")
public class RESTfulHandler {
@GetMapping("/find")
@ResponseBody
public String find()
{
return "Hello";
}
@PostMapping("/save")
public void save(){
}
@PutMapping("/update")
@ResponseBody
public String update(){
return "接收到PUT请求";
}
@DeleteMapping("/delete")
@ResponseBody
public String delete(){
return "已接受到DELETE请求";
}
}
需求分析
jsp
添加jstl依赖
jstl
jstl
1.2
实体类
private Integer id;
private String name;
private Double price;
CourseRepository
@Repository
public class CourseRepository {
private Map courseMap;
public CourseRepository(){
courseMap=new HashMap<>();
courseMap.put(1,new Course(1,"Java基础",Double.parseDouble("500")));
courseMap.put(2,new Course(2,"Java高级",Double.parseDouble("600")));
courseMap.put(3,new Course(3,"企业级框架",Double.parseDouble("800")));
}
public Collection 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);
}
}
改写下index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page isELIgnored="false"%>
Title
编号
名称
价格
${course.id}
${course.name}
${course.price}
修改
CourseController
import com.test.entity.Course;
import com.test.repository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/course")
public class CourseController {
@Autowired
private CourseRepository courseRepository;
@GetMapping("/findAll")
public ModelAndView findAll(){
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("list",courseRepository.findAll());
return modelAndView;
}
@PostMapping("/save")
public String save(Course course){
courseRepository.saveOrUpdate(course);
return "redirect:/course/findAll";
}
@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";
}
}
save.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
edit.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
Title
文件上传
pom.xml引入依赖
commons-io
commons-io
2.6
commons-fileupload
commons-fileupload
1.3.3
JSP页面
input的type设置为file
form表单的method设置为post
form表单enctype设置为multipart/form-data
upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
Title
FileHandler
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
@Controller
@RequestMapping("/file")
public class FileHandler {
@PostMapping("/upload")
public String upload(@RequestParam("img") MultipartFile img, HttpServletRequest request){
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);
request.setAttribute("src","/file/"+fileName);
}
catch (Exception e){e.printStackTrace();}
}
return "upload";
}
}
在springmvc.xml中配解析器
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" %>
Title
controller
@RequestMapping("/uploads")
public String uploads(@RequestParam("imgs") MultipartFile[] imgs,HttpServletRequest request){
List 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 (Exception e){e.printStackTrace();}
}
request.setAttribute("list",pathList);
}
return "uploads";
}
数据校验是每个项目必不可少的模块,SpringMVC提供了两种数据校验的组件:
使用基于Validator接口进行校验会复杂一些,具体数据校验的规则需要开发者手动设置。而使用Annotation JSR-303标准会相对简单一些,开发者不需要编写校验规则,直接通过注解的形式给每一条数据添加验证规则,具体操作是直接在实体类的属性上添加对应的校验注解即可。
例:
创建实体类:
import lombok.Data;
@Data
public class Student {
private String name;
private String password;
}
自定义数据校验器StudentValidation,实现Validation接口,重写接口的抽象方法,加入校验规则。
import com.test.Entity.Student;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class StudentValidation implements Validator {
public boolean supports(Class> aClass) {
return Student.class.equals(aClass);
}
public void validate(Object o, Errors errors) {
ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
ValidationUtils.rejectIfEmpty(errors,"password",null,"密码不能为空");
}
}
ValidateHandler.java
import com.test.Entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@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";
}
}
springmvc.xml配置validator
JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
Title
学生登录
学生姓名:
学生密码:
Hibernater Validator,通过注解完成校验规则的绑定。
@Null 只能为null
@NotNull 不能为null
@Size 设置数据长度
@NotEmpty 不能为空
例:
pom.xml
org.hibernate.validator
hibernate-validator
6.0.11.Final
javax.validation
validation-api
2.0.1.Final
org.jboss.logging
jboss-logging
3.4.1.Final
javax.xml.bind
jaxb-api
2.3.1
com.sun.xml.bind
jaxb-impl
2.3.0
com.sun.xml.bind
jaxb-core
2.3.0
javax.activation
activation
1.1.1
创建实体类,通过注解的方式给属性指定校验规则
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
@Data
public class Account {
@NotEmpty(message = "用户名不能为空")
private String username;
@Size(min=6,max=20,message = "密码长度为6-20位")
private String password;
@Email(regexp = "^[a-z]([a-z0-9]*[-_]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\\.][a-z]{2,3}([\\.][a-z]{2})?$",message = "请输入正确的邮箱")
private String email;
@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "请输入正确的电话格式")
private String phone;
}
业务方法
@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 "register";
}
return "success";
}
springmvc.xml
JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
Title
用户注册
用户名:
密码:
邮箱:
电话:
例:
Student实体类
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
}
import com.test.entity2.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/student")
public class StudentHandler {
@RequestMapping("/get")
public String get(Model model){
Student student=new Student();
model.addAttribute("student",student);
return "student";
}
}
JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
Title
修改学生信息
Handler
import com.test.entity2.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@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";
}
}
JSP页面导入Spring MVC表单标签库
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
将form表单与表单业务数据进行绑定,通过modelAttribute属性完成绑定,将modelAttribute的值设置为控制器想model对象存值时的name即可
学生编号:
学生姓名:
学生年龄:
学生性别:
1.form标签
渲染的时HTML中的 ,通过modelAttribute属性绑定具体业务数据。
2.input标签
渲染的时HTML中的,form绑定的是业务数据,input标签绑定的是业务数据中的属性值,通过path与业务数据的属性名对应,并支持级联。
例:
实体类
import lombok.Data;
@Data
public class Address {
private Integer id;
private String name;
}
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
private Address address;
}
JSP
学生编号:
学生姓名:
学生年龄:
学生性别:
学生地址:
Handler
@RequestMapping("/get")
public String get(Model model){
Student student=new Student();
student.setId(1);
student.setName("张三");
student.setAge(22);
student.setGender("男");
Address address=new Address();
address.setId(1);
address.setName("科技路");
student.setAddress(address);
model.addAttribute("student",student);
return "student";
}
3.password标签
渲染的是HTML中的通过path与业务数据的属性名对应,password标签的值不会在页面显示。
4.checkbox标签
渲染的是HTML中的,通过path与业务数据的属性名对应,可以绑定boolean、数组和集合。
如果绑定boolean类型的变量,该变量值为true则表示选中,false表示不选中。
JSP
checkbox:
如果绑定数组和集合类型,集合中的元素等于checkbox的value值,则该项选中,否则不选中。
JSP
读书
看电影
打游戏
听音乐
旅行
5.checkboxs标签
渲染的是HTML中的一组,这里需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定选中的集合或数组items是全部选型,path为默认选中的选型
student.setHobby(Arrays.asList("读书","看电影","旅行"));
student.setSelectHobby(Arrays.asList("读书","看电影"));
JSP
需要注意的是path可以直接绑定业务数据的属性,items则需要通过EL表达式从域对象中取值,不能直接写属性名。
6.radiobutton
渲染的是HTML中的一个,绑定的数据与标签的value值相等为选中状态,否则为不选中状态。
private Integer radioId;
JSP
男
女
7.radiobuttons标签
渲染的是HTML中的一组,这里需要结合items和path两个属性来使用,item绑定被遍历的集合或数组,path绑定被选中的值,items是全部选型,path为默认选中的选型。
Map gradeMap=new HashMap<>();
gradeMap.put(1,"一年级");
gradeMap.put(2,"二年级");
gradeMap.put(3,"三年级");
gradeMap.put(4,"四年级");
gradeMap.put(5,"五年级");
gradeMap.put(6,"六年级");
student.setGradeMap(gradeMap);
student.setSelectGrade(3);
JSP
8.select标签
渲染的是HTML中的一个,这里需要结合items和path两个属性来使用,items绑定被遍历的集合或数组,path绑定被选中的值,用法与标签一致。
Map cityMap=new HashMap<>();
cityMap.put(1,"北京");
cityMap.put(2,"上海");
cityMap.put(3,"广州");
cityMap.put(4,"深圳");
student.setCityMap(cityMap);
student.setSelectCity(2);
JSP
9.form:select标签结合form:options使用
form:select只定义path属性,在form:select标签内部添加一个子标签form:options,设置items属性
10.form:select标签结合form:option使用
form:select定义path属性,给每一个form:option设置value属性,path与哪个value相等,该项默认选中。
西安
杭州
成都
国际化是指同一个应用程序在不同语言设置的浏览器中,自动显示不同的语言,Spring MVC对国际化操作做了很好的集成,只需要简单的配置即可实现国际化。
1.springmvc.xml中配置
创建国际化资源文件language_en_US.properties,language_zh_CN.properties,分别存储英文和中文资源
language_en_US.properties
language.en = English
language.cn = \u4e2d\u6587
info = login
username = username
password = password
repassword = repassword
tel = tel
email = email
submit = submit
reset = reset
language_zh_CN.properties
language.en = English
language.cn = \u4e2d\u6587
info = \u767b\u5f55
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
Handler
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/inter")
public class InterHandler {
@GetMapping("/index")
public String index(){
return "inter";
}
}
JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
Title
English
中文