Java - 框架 - SpringMVC
一、项目搭建
-
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.17.RELEASE</version>
</dependency>
</dependencies>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8082</port>
<path>/</path>
<uriEncoding>utf-8</uriEncoding>
</configuration>
</plugin>
</plugins>
-
web.xml <filter>
<filter-name>encodeFilter</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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
如果报错:
The content of element type “web-app” must match "(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)
解决方法:
将filter代码放到servlet上面,就可以解决
原理:
按照web.xml中的映射配置顺序按照配置条件从后向前调用第一个满足条件的Servlet,调用之前事先执行满足条件的Filter,不存在层次调用Servlet问题
参考文章:
Filter与Servlet的区别与联系_随风飘扬-CSDN博客_filter和servlet
-
applicationContext.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.xsd">
<context:component-scan base-package="com.spring"></context:component-scan>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
-
Controller.java @Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/query")
public String query(){
System.out.println("query.........");
return "index";
}
}
二、SpringMVC响应请求
2.1 不响应请求
如果用户提交了请求后服务端不需要给客户端一个响应,那么我们可以指定返回类型为void 同时在方法头部添加@ResponseBody 注解即可
@RequestMapping("/save")
@ResponseBody
public void add(){
System.out.println("save ..... ");
}
2.2 响应返回字符串
我们可以在处理方法的最后返回一个要跳转的页面地址”/“不要漏了
@RequestMapping("/query")
public String query(){
System.out.println("query ..... ");
return "index";
}
2.3 返回ModelAndView
我们也可以直接返回一个ModelAndView对象
@RequestMapping("/delete")
public ModelAndView delete(){
System.out.println("delete ..... ");
ModelAndView mm = new ModelAndView();
mm.setViewName("/index.jsp");
return mm;
}
2.4 重定向跳转
有些情况下重定向跳转也是我们开发中必须使用的形式
@RequestMapping("/update")
public String update(){
System.out.println("update ..... ");
return "redirect:/user/query";
}
2.5 通过HttpServletResponse响应
仅仅只需要在方法的形参中声明这两个变量即可~
@RequestMapping("/fun1")
public void fun1(HttpServletRequest request
,HttpServletResponse response) throws Exception {
System.out.println("fun1 ...");
request.getRequestDispatcher("/index.jsp").forward(request,response);
}
三、SpringMVC接收请求
3.1 基本数据类型
直接在形参中声明要接收的数据,默认情况下形参必须和传过来的数据参数名一致
@RequestMapping("/query")
public String query(@RequestParam(value = "ids",required = true,defaultValue = "123") Integer id, String name){
System.out.println("query ..... " + id + ":" + name);
return "/index.jsp";
}
3.2 对象接收
如果传递过来的数据比较多,那么我们可以通过一个自定义的对象来接收
@RequestMapping("/save")
public String add(User user){
System.out.println("save ..... " + user);
return "/index.jsp";
}
@Component
public class User {
private Integer id;
private String name;
}
3.3 通过数组接收
如果有多个名称相同的数据提交,我们可以使用数组的方式来接收
@RequestMapping("/delete")
public String delete(String[] loves){
System.out.println("delete ..... ");
if(loves !=null){
for(String l : loves){
System.out.println(l);
}
}
return "/index.jsp";
}
注意:在形参中我们不能够通过集合的方式来获取传递的参数
在自定义对象中可以使用集合获取数组的形式来接收请求的参数
3.4 自定义转换器
有时候客户端传递过来特殊类型的数据,SpringMVC中提供的默认的转换器不能支持该转换,此时我们就需要自定义转换器
package com.gupaoedu.convert;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConvert implements Converter<String,Date> {
@Override
public Date convert(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
applicationContext.xml配置文件
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"
id="formattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.gupaoedu.convert.DateConvert"/>
</set>
</property>
</bean>
四、SpringMVC返回数据
4.1 ModelAndView传递
@RequestMapping("/query")
public ModelAndView query(){
System.out.println("query ..... ");
ModelAndView mm = new ModelAndView();
mm.setViewName("/user.jsp");
mm.addObject("msg","msg.....");
return mm;
}
然后在jsp页面中通过EL表达式获取传递的信息
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
hello<br>
${msg}
</body>
</html>
4.2 通过Map对象传值
ModelAndView使用起来稍微有点复杂,我们可以通过Map来简化操作
@RequestMapping("/save")
public String add(Map<String,Object> map){
System.out.println("save ..... ");
map.put("msg","map ...msg");
return "/user.jsp";
}
4.3 通过Model来接收
@RequestMapping("/delete")
public String delete(Model model){
System.out.println("delete ..... ");
model.addAttribute("msg","model ...msg");
return "/index.jsp";
}
4.4 通过ModelMap响应数据
@RequestMapping("/update")
public String update(ModelMap mm){
System.out.println("update ..... ");
mm.put("msg","ModelMap ... msg");
return "/index.jsp";
}
前面介绍的多种方式的数据都是会被保存在request作用域中,如果我们同时需要将数据保存在Session对象中,我们只需要在类的头部添加一个@SessionAttributes注解即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQSIlAwA-1635304366727)(C:/Users/lWX1096948/Downloads/8.5 SpringMVC之高级进阶/8.5 SpringMVC之高级进阶/01-课件笔记/img/1598431973792.png)]
五、SpringMVC文件
5.1 文件上传
5.1.1 依赖的引入
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
5.1.2 表单页面
提交的方式必须是post 方式,提交的数据的类型必须是二进制文件
<html>
<body>
<h2>Hello World!</h2>
<form action="/user/save" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="username"><br>
头像:<input type="file" name="headImg"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
5.1.3 控制处理
提交的文件我们可以通过 MultipartFile 类型来接收
@RequestMapping("/save")
public String add(MultipartFile headImg,String username) throws IOException {
System.out.println(username);
System.out.println("文件名称:" + headImg.getOriginalFilename());
headImg.transferTo(new File("d:/" + headImg.getOriginalFilename()));
return "/index.jsp";
}
5.1.4 配置文件处理
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
5.2 文件下载
@RequestMapping("/download")
public void download(HttpServletRequest request,
HttpServletResponse response){
File file = new File("d://PC软件安装与环境准备.docx");
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
try {
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(file.getName(),"utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
InputStream in = new FileInputStream(file);
ServletOutputStream out = response.getOutputStream();
byte[] b = new byte[1024];
int num = 0;
while ((num = in.read(b)) != -1){
out.write(b,0,num);
}
out.close();
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
5.3文件展示
默认的情况下在SpringMVC中只能访问jsp页面,其他的都会被DispatchServlet 拦截,原因是DispatchServlet 配置的时候用的/ 覆盖掉了default servlet所做的工作,
- 重新覆写
DispatchServlet
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
六、Controller数据验证
6.1 校验注解实现
-
引入依赖 SpringMVC本身是没有提供校验框架的,我们需要使用Hibernate提供的校验框架 <dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.0.Alpha1</version>
</dependency>
-
在配置文件中注册对应的校验框架
<mvc:annotation-driven validator="validated"/>
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" id="localValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<property name="validationMessageSource" ref="messageSource" />
</bean>
<bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource">
<property name="basename" value="classpath:volidata.properties"/>
<property name="fileEncodings" value="utf-8"/>
<property name="cacheSeconds" value="120"/>
</bean>
-
实现pojo对象 import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotNull;
@Component
@Data
public class User {
@Length(message = "name长度为3-6",max = 6,min = 3)
private String name;
@NotBlank(message = "{user.sex.isnull}")
private String sex;
@NotNull(message = "id不能为空")
private Integer id;
}
-
Controller对象实现 @RequestMapping("add")
public ModelAndView add(@Validated User user, BindingResult br){
System.out.println(user);
ModelAndView modelAndView = new ModelAndView();
List<ObjectError> errors = br.getAllErrors();
modelAndView.setViewName("/user.jsp");
for (ObjectError error :errors){
System.out.println(error.getDefaultMessage());
modelAndView.addObject("error",error.getDefaultMessage());
}
if (errors.size()>0){
return modelAndView;
}
else{
modelAndView.addObject("id",user.getId());
modelAndView.addObject("name",user.getName());
modelAndView.addObject("sex",user.getSex());
}
return modelAndView;
}
-
jsp对象实现 <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<body>
<h2>Hello World!</h2>
<form action="/test/add" method="get" >
id:<input type="text" name="id"><br>
name:<input type="text" name="name"><br>
sex:<input type="text" name="sex"><br>
<input type="submit" value="提交">
</form>
<h1>${error}</h1>
id:${id}<br>
name:${name}<br>
sex:${sex}
</body>
</html>
-
注意点:
-
如果在实现过程中发现配置文件中读取的内容是乱码,调整idea的配置文件编码格式 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o25FdbGS-1635435032548)(C:/Users/Apricity/AppData/Roaming/Typora/typora-user-images/image-20211028231154766.png)]
6.2 常用校验注解
验证规则
注解 | 说明 |
---|
@Null | 被注解的元素必须为 null | @NotNull | 被注解的元素必须不为 null | @AssertTrue | 被注解的元素必须为 true | @AssertFalse | 被注解的元素必须为 false | @Min(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 | @Max(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 | @DecimalMin(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 | @DecimalMax(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 | @Size(max=, min=) | 被注解的元素的大小必须在指定的范围内 | @Digits (integer, fraction) | 被注解的元素必须是一个数字,其值必须在可接受的范围内 | @Past | 被注解的元素必须是一个过去的日期 | @Future | 被注解的元素必须是一个将来的日期 | @Pattern(regex=,flag=) | 被注解的元素必须符合指定的正则表达式 | @NotBlank(message =) | 验证字符串非null,且长度必须大于0 | @Email | 被注解的元素必须是电子邮箱地址 | @Length(min=,max=) | 被注解的字符串的大小必须在指定的范围内 | @NotEmpty | 被注解的字符串的必须非空 | @Range(min=,max=,message=) | 被注解的元素必须在合适的范围内 |
6.3 分组校验
分组验证解决的是不同的同一个POJO对象在不同的场景用适用不同的验证规则
-
实现分组接口 public interface MyVal1 {
}
public interface MyVal2 {
}
-
实现bean对象 @Component
@Data
public class User {
@Length(message = "name长度为3-6",max = 6,min = 3,groups = MyVal1.class)
private String name;
@NotBlank(message = "{user.sex.isnull}",groups = {MyVal1.class})
private String sex;
@NotNull(message = "id不能为空",groups = {MyVal1.class, MyVal2.class})
private Integer id;
}
-
实现分组校验 @RequestMapping("/save")
public String add(@Validated({MyVal1.class}) User user, BindingResult br, Model model) throws IOException {
System.out.println("save ....");
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError error:allErrors){
System.out.println(error.getDefaultMessage());
}
return "/index.jsp";
}
@RequestMapping("/update")
public String update(@Validated({MyVal2.class}) User user, BindingResult br, Model model) throws IOException {
System.out.println("update ....");
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError error:allErrors){
System.out.println(error.getDefaultMessage());
}
return "/index.jsp";
}
七、SpringMVC拦截器
定义自己的拦截器类
package com.springmvc.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("preHandle....");
return true;
}
@Override
public void postHandle(HttpServletRequest request
, HttpServletResponse response
, Object handler, ModelAndView modelAndView) {
System.out.println("postHandle ....");
}
@Override
public void afterCompletion(HttpServletRequest request
, HttpServletResponse response
, Object handler, Exception ex) {
System.out.println("afterCompletion....");
}
}
在配置文件中加上自定义的拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.springmvc.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
|