目录
目录
kuang:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!--EL表达式的标签支持-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
springMVC乱码过滤
配置web.xml
/ 过滤的不是所有的请求,像页面的jsp请求不过滤,需要修改路径 /*
配置位置
json
导入jackson jar包
前后台分离 在使用json格式的乱码问题 固定写法
springmvc框架给我们提供的,
使用json格式,1 导入jar, 2 解决json乱码问题 3 使用ObjectMapper对象转换成json,
@RestController
如果使用@RestController 那么返回的数据格式只能是json格式,视图解析器是不会走的,@RequestBody也是这个作用,当用了@RestController时就可以不用。
返回日期方式
或者也可以使用SimpleDateFormat方法
FastJson
简单
技术点
概念:
springMVC框架技术,把spring和mybatis技术结合到视图层。
基于MVC结构,请求驱动类型的轻量级web框架,属于spring框架的后续设计
它有很多的控制器,不需要实现任何接口,同时支持RESTFUL编程风格。
resultful编程风格:我们用的get方式提交 "?username=haha&password=123456"的形式
就是resultful编程风格。
SpringMVC 控制器
1、前端控制器 在web.xml中配置,作用是客户端和服务器的交互,其实就是Javaweb中的
servlet。
2、请求到处理器映射(控制类) 通过注解配置@Controller 和@RequestMapping(path =
"/hello") 实现在页面中请求到处理器处理请求的映射。
3、视图解析器 解析处理器中return "success",通过视图解析器解析为jsp文件这个jsp文件的
名字要跟return返回的字符串一样才能被识别到,响应给浏览器。
MVC中页面不是通过跳转完成的,不像javaWeb,是通过代码中的返回值,视图解析器会
把返回值解析成jsp页面用户显示。
4、处理器或者页面控制器
5、验证器
6、命令对象
7、表单对象
搭建SpringMVC的框架结构
解决maven项目创建过慢的问题
标记为功能目录
1、添加依赖坐标
1)<maven.compiler.target>1.8</maven.compiler.target>
注意选择与我们使用的jdk版本要一致
配置servlet和jsp是因为servlet和jsp在springMVC框架中是为了我们编写代码时用的,而运行时用的是Tomcat上的servlet和jsp。所以需要设置作用域使只在编译时有效。
scope 作用域: provided使编译器有效。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
2) pom.xml坐标依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- 版本锁定 -->
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</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-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
2、配置前端控制器web.xml:
它在org.springframework…….DispatcherServlet类中,通过map映射指明只要在 / 路径下就能找到前端控制器,并通过初始化参数让程序在加载web.xml前端控制器同时也能加载springMVC.xml配置文件。
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3、创建SpringMVC配置文件
<!--添加注解扫描-->
<context:component-scan base-package="com.neuedu"></context:component-scan>
配置tomcat服务器
小知识:建工程自带的index.jsp里面是没有设置字符集的,我们不想写可以把工程带的删掉,自己在创建一个jsp文件就自动带基础的配置了
添加约束
配置开启SpringMVC的注解
狂的配置:
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.quxingtao.controller"/>
<mvc:default-servlet-handler/><!--过滤静态资源 CSS,HTML等-->
<mvc:annotation-driven/><!--配置 HeadlerMapping和HandlerApapter两个实例-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--视图解析器-->
<property name="prefix" value="WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
控制器
4、控制器类实现
创建控制器类
@Controller代表这是一个控制器类,否则通过IOC容器创建对象
在访问页面发送请求时通过@RequestMapping注解在页面映射路径找到这个方法。
配置标签
<load-on-startup>1</load-on-startup>
这个标签目的是启动servlet就先加载init-parm文件,会先扫描sprinMVC中的注解的信息。
5、配置视图解析器:
视图解析器其实是官方封装好的类,我们只需要把视图解析器的对象放在ico容器,
name = “prefix”叫做前缀,说明要指向的路径value = “”
value = “/pages/”
告诉视图解析器要解析路径位置,视图解析器便会拿我们在控制器类中return返回的字符串去找对应名字的jsp文件进行解析显示。
/ 代表web资源的根目录
name="suffix" value=".jsp"
给解析器指明路径下找的文件是 .jsp格式的文件
<!--配置视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
然后如下图所示运行就可以在页面中查看解析结果
SpringMVC执行流程 (面试)
1、web工程就需要启动Tomcat服务器,启动后自动加载我们以下配置的文件
在web.xml中配置一些信息
1)DispatcherServlet 创建了一个对象 叫做前端控制器(控制请求信息)
前端通过它实现对接、获取,拿到获取的数据往后面给下一步,
2)在它的内部配置了一个信息(classpath:springMVC.xml),目的是加载xml配置文件。
3)加载完配置文件后到springMVC.xml文件中加载,
4)扫描到注解@Controller修饰的HelloController类文件(控制器),这时
HelloControlle 对象被创建。
2、浏览器要访问服务器资源,发送请求,服务器处理请求信息
1)请求首先要找控制它对应的控制器,那就是HelloController控制器类,
2)控制器类中有多个方法,具体哪个方法控制要看请求的路径和映射路径要一致,
3)处理方法中要处理具体的请求信息(调用Spring(下一层)进行业务逻辑处理),并且返
回字串,对字符串进行视图解析找到对应的jsp文件。
3、响应
通过视图解析的jsp文件,响应给客户端浏览器
在代码运行角度看控制器的作用:
客户端点击超链接发起访问,直接访问到web.xml中配置的前端控制器DispatcherServlet(起到指挥作用),控制器再指挥到注解对应的控制类处理,通过控制类找到springMVC.xml中的视图解析器,通过视图解析器解析成jsp文件(success.jsp)再通过控制器回到客户端。
@RequestMapping注解
作用:用于建立页面中请求的地址(URL路径)和处理请求(控制器类)的方法实现对应的映射连接。
作用的位置:
1、类上可使用
表示请求的url是第一级访问目录,如果该位置上不写url,那么相当于web应用的根目录 /。
2、方法上可使用
如果有类上使用的形式,那么方法上是表示第二级目录。
属性:path =”目录”
属性:value 用于指定请求的url,和path作用一样
属性:method 用于请求方式 get post
属性:params 用于指定限制请求参数的条件 支持一些简单的表达式
要求请求参数有key和value映射关系。
属性:headers:用于指定限制请求消息头的条件
相当于请求过来的信息要有”haha”才会识别,没有就不识别
SpringMVC的参数绑定
作用:为页面提供了一种方式,可以在Java程序中(后台)获取对应的页面表单数据信息进行操作,如自动封装成对象。
绑定机制:(要求)
1)提交的数据(表单) 必须遵循键值对的形式 key=value
username=haha&password=123456
2)提交的表单数据,作为控制器类方法中的参数进行绑定。
3)要求提交的表单name属性和方法参数的名称是相同的。
绑定参数支持数据类型:
1)基本数据类型和String类型
@RequestMapping("/testParam")
public String testParam(String username){
System.out.println("用户名:" + username);
return "success";
}
<a href="/param/testParam?username=haha">请求参数绑定——用户名</a>
2)实体类型(JavaBean类型)
1.依然是表单中name属性和参数名字一致
2.如果一个实体类中包含其他的引用类型,那么表单的name要写成:对象.属性
如果一个实体类中包含其他的引用类型(一对一),那么表单的name要写成:对象.属性
在上一个例子中添加引用类型演示
<%--一定是为了封装实体类对象--%>
<form action="/param/saveAccount" method="post">
姓名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
金额:<input type="text" name="money"><br>
用户姓名:<input type="text" name="user.uname"><br>
用户年龄:<input type="text" name="user.age"><br>
<input type="submit" value="提交">
</form>
3)集合类型(List Set Map)
list[0].属性
用户姓名:<input type="text" name="list[0].uname"><br>
用户年龄:<input type="text" name="list[0].age"><br>
用户姓名:<input type="text" name="map['one'].uname"><br>
用户年龄:<input type="text" name="map['one'].age"><br>
解决中文乱码问题
设置过滤器 Spring提供的
配置需要在web.xml文件中实现
<!--配置过滤器,解决的是过滤中文乱码问题-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
以上操作等价于我们之前学JavaWeb的表单提交(getParameter)
SpringMVC 重要点:
1、参数绑定(页面数据和具体的控制器的处理方法实现对应关系)(重点)
2、注解(重点) 使用注解比较多
3、返回值类型 返回值需要通过视图解析器成jsp还需要带一些不同的数据类型显示。可通过注解去使用(重点)
4、SpringMVC上传文件
5、拦截器
SpringMVC注解
五个掌握。两个了解
前提:
开始SpringMVC的注解扫描
<!--为了我们能使用SpringMVC的注解-->
<mvc:annotation-driven></mvc:annotation-driven>
1)RequestParam
作用:是将请求中页面指定名称的参数给控制器中的方法的形参赋值
属性:
name : 请求参数中的名称 页面中name
value 与name的作用一样
required 请求参数中是否必须提供此参数,默认值是true表示必须提供
(了解,每一个注解都有这个属性)
2)RequestBody
(在异步通讯中使用 等同JavaWeb中的ajax技术交互时使用)
作用:用于获取请求体内容(表单),得到的格式是key=value结构的数据
注意:get方式不适用, username=haha&password=123
所以只能使用post请求方式
3)PathVaribale
作用:针对用于参数绑定url中的占位符,例如请求url中 /xxx/{id}
{id} 我们可以给任意的值 叫做{id}占位符 在书写过程直接写值就可以,只是值可以变化
restful风格 这是springMVC支持restful风格的一个重要标志
使用场景:页面访问时可以顺便把值带到控制器类中,并给到类中的参数.
4)RequestHeader(使用较少,了解)
作用:获取请求中的消息头(比如获取cookie中的JSESSIONID)
5)CookieValue(使用较少,了解)
作用:将指定cookie名称的值传入控制器类中方法参数
属性:value和name 指定cookie的名称
6)ModelAttribute(重要的)
用于修饰方法和参数
1) 修饰方法,表示当前方法会在控制器的方法执行之前,先执行。
比如说在控制器类需要处理的方法之前,先执行此注解修饰的方法
可以有返回值也可以没有
2) 修饰参数 获取指定的数据给参数赋值
应用场景:
场景:当页面数据提交不是完整的实体类数据时或者遗漏,放入数据库可能会影响操作
为了保证后续操作,可以使用数据库原有属性,利用ModelAttribute注解提前把遗漏数据填充
进实体类中去封装,在让控制类去处理信息。
实例:编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许修改的,在提交表单数据时肯定没有该字段的内容,一旦更新时候会将该字段的内容设置为null,这个时候可以用该注解解决
7)SessionAttributes
该注解声明共享数据,由ModelMap的get方法取出。
用于多次执行控制器方法间的参数共享 实际来说就是Javaweb中的作用域
利用SessionAttributes将msg=哈哈 存入到session域中
本质:将存入request域对象中的数据,存入session域对象
使用注解@SessionAttributes
清除session中的共享数据
SpringMVC返回值类型
三种方法都可以实现页面的跳转
1)返回字符串(常用)
返回字符串实现找到对应的jsp文件(通过视图解析器实现的)
/**
* 返回字符串
* */
@RequestMapping("/testString")
public String testString(Model model){
//调用service层 处理逻辑,通过service实现调用持久层操作数据库
//模拟数据的操作
User user = new User();
user.setUname("哈哈");
user.setAge(20);
model.addAttribute("user", user);
return "success";
}
使用视图解析器需要在springMVC.xml中配置
2)返回void(在框架不提倡使用)
/**
* 返回值是void 不是我们提倡在框架中使用的
* 操作的时候是和我们之前JavaWeb中的servlet技术操作是一样的
* */
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求转发
request.getRequestDispatcher("/pages/success.jsp").forward(request,response);
//重定向
response.sendRedirect(request.getContextPath()+"/index.jsp");
}
3)返回ModelAndView(类)
类中的方法有addObject(“”,xxx) 声明到域对象中,
mv.setViewName("success"); 跳转到哪个页面,在页面中EL表达式取出${requestScope.xxx}
是SpringMVC固定提供的一个对象(可以作为控制器方法的返回值)
也可以存到域对象中
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
//模拟数据的操作
User user = new User();
user.setUname("哈哈");
user.setAge(20);
//将user对象存储到mv对象中,也会将user对象存储到request域中
mv.addObject("user", user);
//跳转到哪个页面
mv.setViewName("success");
return mv;
}
框架中可以实现重定向和转发方式
请求转发
重定向
这个路径注意修改(是项目的根目录就/文件名.jsp)
注意:如果是重定向到jsp页面,jsp文件不能写在WEB-INF下面
(WEB-IN目录都是一些配置的文件,不是我们常用的)
/**
* 按照框架的方式写请求转发和重定向
*/
@RequestMapping("/testForwardandRedirect")
public String testForwardandRedirect(){
System.out.println("testForwardandRedirect方法执行了...");
//请求转发 也可以转发到其他的控制器
//return "forward:/pages/success.jsp";
//相当于使用
// request.getRequestDispatcher("/pages/success.jsp").forward(request,response);
//重定向
return "redirect:/index.jsp";
//response.sendRedirect(request.getContextPath()+"/index.jsp");
//注意:如果是重定向到jsp页面,jsp文件不能写在WEB-INF下面
}
响应数据类型
json(重要),xml
@ResponseBody响应json数据格式,跟之前axjx的异步操作是一样的,只不过把ajax中servlet换成注解方式实现的
作用:注解将Controller类的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据(json),响应给客户端浏览器
前提:需要导入新的坐标依赖
jar包支持(json解析器)
jackson
步骤
1)导入jackson依赖坐标和Jquery
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
注意:前端控制器会进行静态资源的拦截
2)当我们导入静态资源的时候,SpringMVC是没有对应的反应的
原因:DispatcherServlet前端控制器会进行静态资源的拦截
解决方式:
1、重新设置一下web.xml,要求它不能拦截静态资源springMVC.xml
<!--前端控制器,不会拦截一下静态资源-->
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
2、默认的拦截方式
springMVC框架对名字过长有bug,需要把jquery的包修改名字为jquery.js
<mvc:default-servlet-handler></mvc:default-servlet-handler>
3)编写jquery代码, 添加对应的ajax请求
添加对应的ajax请求
$.ajax({
//json格式,设置属性名和属性值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"uname":"haha","age":"20"}',
dataType:"json",
type:"post",
success:function (data) {
//服务器响应的json数据,进行解析
alert(data.uname);
alert(data.age);
}
});
4)控制器实现
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了...");
System.out.println(user);
//做出对应的响应
//模拟数据操作
user.setUname("呵呵");
user.setAge(40);
//做出响应
return user;
}
SpringMVC文件上传
概述
两种形式
1)利用框架自带的文件上传功能
2)不利用框架,利用第三方插件实现上传
这两种形式实现文件上传的前提(前台页面):
1)form表单中属性enctype的值必须是multipart/form-data
2)method属性必须是post
3)提供一个上传的控件 <input type="file">
前台页面满足这三点才能实现上传的操作
SpringMVC上传原理
新建工程:(内容知识点全面)
pom.xml
<!--版本锁定-->
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</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-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
springMVC.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.neuedu"></context:component-scan>
<!--视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/pages/"></property>
<property name="suffix" value=".jsp"></property><!--给解析器指明路径后解析成 .jsp格式 -->
</bean>
<!--开启spingMVC注解-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--前端控制器,不会拦截一下静态资源-->
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
</beans>
web.xml
<display-name>Archetype Created Web Application</display-name>
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name><!--name固定写法-->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!--目的是启动servlet就先加载init-parm文件,先扫描注解的信息-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置过滤器 解决参数绑定中文乱码问题-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--加入初始化参数,指明过滤UTF-8-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
实现步骤
1)上传所需要的依赖
pom文件需要导入坐标依赖
<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>
2)配置文件解析器
1024进制 B KB MB GB
<!--配置文件解析器,要求id名字必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
3)配置上传的控件, 前台页面
以下固定操作:
enctype="multipart/form-data"
method="post"
<form action="/user/fileupload" method="post" enctype="multipart/form-data">
文件的选择:<input type="file" name="upload"><br>
<input type="submit" value="上传">
</form>
4)最终上传
UUID 作用:作为服务存放图片的唯一标识,作用就是为了不让不同的客户端上传的图片发生覆盖
核心的东西就这三步:
//上传文件存放的位置
String path = request.getSession().getServletContext().getRealPath("/upload/");
//获取上传文件的名字
String fileName = upload.getOriginalFilename();
//完成上传 path 传来的文件需要存放到的位置 fileName存放文件的名字
upload.transferTo(new File(path,fileName));
目录target:上传生成文件存放在目录是target。包括生成的class文件
SpringMVC拦截器
概述:
属于SpringMVC框架下一个特殊功能,其他结构是不能使用的
作用:对处理器进行预处理和后处理的技术,后处理的技术包括处理方法执行后和页面执行完后做什么
可以定义一个拦截器链,类似于之前的过滤器链
拦截器链:按照有一定的顺序结构,去拦截对应的访问方法
拦截器和过滤器进行比较?(面试概率不是很高)
1、过滤器是Servlet规范的一部分,任何框架结构都是可以使用过滤器的(springMVC也是可以使用过滤器的,但是过滤器只是针对于页面表现层,因为过滤的是页面访问的信息)
2、拦截器是SpringMVC的独有功能
3、过滤器配置这种写法/*,是可以过滤任何资源,也可以指定单独的资源进行过滤
4、拦截器只会对控制器中的方法进行拦截
5、拦截器是AOP思想实现的功能
6、SpringMVC下我们只需要配置xml文件就可以实现过滤器
7、实现拦截器,需要实现HandlerInterceptor接口
操作步骤(一个拦截器):
1)编写一个普通的类,让该类实现HandlerInterceptor接口,那么它就是一个拦截器
public class MyInterceptor implements HandlerInterceptor
2)实现该接口中的方法(和AOP中的通知是一样的,为了增强对应的控制器的处理方法)
Ctrl + o 快捷键可以实现接口方法的重写
HandlerInterceptor接口中的三个方法:
第一个:preHandle() 预处理(在执行处理控制器中的方法之前先执行)
如果返回值是true,表示不拦截(放行),如果有后续拦截器,那么继续看是否拦截,如果不拦截,执行控制器中的具体方法
如果返回值false,不会执行控制器中的方法
request或response可以跳转执行页面,如果指定了跳转的页面,控制器也可以跳 不影响控制器类中的方法
第二个:postHandle() (后处理 在执行处理控制器中的方法后执行)
是在控制器方法执行之后,但是在jsp执行之前 需要执行的方法,
request或response可以跳转执行页面,如果指定了跳转的页面,
那么会影响控制器方法中的跳转就失效
第三个:afterCompletion() 也是后执行是最终处理,(它是在页面完成后执行处理)
jsp页面执行后执行 如果使用request或response不能跳转页面,因为页面加载完了
3)配置拦截器,xml文件(建立拦截器类和控制器类建立上关联)
/**
<!--配置拦截器部分-->
<mvc:interceptors>
<!--配置第一个拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/**"/>
<!--配置拦截器对象。并把它交给IOC容器,程序内部自动执行,
我们不需要配置id去使用这个对象-->
<bean class="com.neuedu.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
实现拦截器接口的方法,配置return的放回值false,那么请求就被隔离。访问不到controller
多个拦截器
跟一个拦截器原理是一样的,只是拦截的功能是不一样的(比如一个包下的不同控制器类)
在实现的时候——主要是到底是横向排列还是纵向排列(了解)
主要配置拦截器xml文件
<!--配置第一个拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/abc"/>
<!--<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="com.neuedu.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<!--配置第二个拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/abc"/>
<!--<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="com.neuedu.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
框架下异常处理
概述
在一系列操作中可能会出现异常:
浏览器发出请求-->前端控制器 --> 表现层 --> 业务逻辑层 --> 持久层
错误页面 异常处理器组件 抛出 抛出 <-- 出现异常抛出
交给异常处理的类
如果持久层出现异常抛出
业务逻辑层接收到持久层的异常也抛出
表现层同理抛出
前端控制器接收到下层出现的异常,然后使用异常处理器组件(catch{}的意思),交给异常处理的类
最后交给浏览器出现错误页面
注意:如果不给出错误页面,客户端能看到的就是异常信息(比如404)
实现步骤:
出现错误时,通过springMVC.xml文件中配置的异常处理器把错误截住,不让显示在页面中。截住的异常在异常处理器类(实现一个接口HandlerExceptionResolve)中处理,在异常处理器类中自定义一个异常类,把我们自定义异常的信息通过接口的ModelAndView对象,存在域对象中跳转到显示异常的页面,在由显示异常的页面通过EL表达式获取域对象中的数据,让客户看到
1)编写一个自定义异常类,所有的自定义异常类都要继承Exception类
/**
* 自定义异常
* */
public class SysException extends Exception{
//存储提示信息,用于提示页面
private String message;
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
//构造方法,当调用这个方法就把自定义异常的信息初始化
public SysException(String message){
this.message = message;
}
}
2)编写异常显示的页面
error.jsp,直接用文字显示就可以,使用异常处理类中通过域对象共享的数据出现在提示异常的页面
浏览器请求的页面:
3)自定义异常处理器 处理的信息是我们自己写
实现一个接口HandlerExceptionResolver
实现接口中的方法,这个方法是写业务逻辑处理的方法
如果有异常我们需要拿到我们自定义异常的对象。出现异常的类要判断我们自定义异常类是否是它的子类,如果不是那么使用我们自定义的异常类,显示给用户。如果出现异常的类是我们自定义类的父类,那么也得只用我们自定义的异常,否则出现异常客户会看不到我们自己定义的异常
4)在前端控制器xml文件中配置异常处理器。让配置文件识别到异常处理器
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.neuedu.exception.SysExceptionResolver"></bean>
制造异常 测试代码
SpringMVC:拦截器+文件上传下载
拦截器kuang
概述
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
-
servlet规范中的一部分,任何java web工程都可以使用
-
在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
-
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
-
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
自定义拦截器
那如何实现拦截器呢?
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
1、新建一个Moudule , springmvc-07-Interceptor , 添加web支持
2、配置web.xml 和 springmvc-servlet.xml 文件
3、编写一个拦截器
package com.kuang.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 {
//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}
//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}
//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}
4、在springmvc的配置文件中配置拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.kuang.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5、编写一个Controller,接收请求
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//测试拦截器的控制器
@Controller
public class InterceptorController {
@RequestMapping("/interceptor")
@ResponseBody
public String testFunction() {
System.out.println("控制器中的方法执行了");
return "hello";
}
}
6、前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
7、启动tomcat 测试一下!
验证用户是否登录 (认证用户)
实现思路
1、有一个登陆页面,需要写一个controller访问页面。
2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
测试:
1、编写一个登陆页面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<h1>登录页面</h1>
<hr>
<body>
<form action="${pageContext.request.contextPath}/user/login">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="pwd"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
2、编写一个Controller处理请求
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class UserController {
//跳转到登陆页面
@RequestMapping("/jumplogin")
public String jumpLogin() throws Exception {
return "login";
}
//跳转到成功页面
@RequestMapping("/jumpSuccess")
public String jumpSuccess() throws Exception {
return "success";
}
//登陆提交
@RequestMapping("/login")
public String login(HttpSession session, String username, String pwd) throws Exception {
// 向session记录用户身份信息
System.out.println("接收前端==="+username);
session.setAttribute("user", username);
return "success";
}
//退出登陆
@RequestMapping("logout")
public String logout(HttpSession session) throws Exception {
// session 过期
session.invalidate();
return "login";
}
}
3、编写一个登陆成功的页面 success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录成功页面</h1>
<hr>
${user}
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>
4、在 index 页面上测试跳转!启动Tomcat 测试,未登录也可以进入主页!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<h1>首页</h1>
<hr>
<%--登录--%>
<a href="${pageContext.request.contextPath}/user/jumplogin">登录</a>
<a href="${pageContext.request.contextPath}/user/jumpSuccess">成功页面</a>
</body>
</html>
5、编写用户登录拦截器
package com.kuang.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
// 如果是登陆页面则放行
System.out.println("uri: " + request.getRequestURI());
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用户已登陆也放行
if(session.getAttribute("user") != null) {
return true;
}
// 用户没有登陆跳转到登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
6、在Springmvc的配置文件中注册拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="com.kuang.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
7、再次重启Tomcat测试!
OK,测试登录拦截功能无误.
文件上传和下载kuang
准备工作
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的 enctype 属性做个详细的说明:
-
application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
-
multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
-
text/plain:除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
-
Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
-
而Spring MVC则提供了更简单的封装。
-
Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
-
Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:
-
CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
文件上传
1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
2、配置bean:multipartResolver
【注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!】以下的文件大小上线和单位可以不配
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
CommonsMultipartFile 的 常用方法:
-
String getOriginalFilename():获取上传文件的原名
-
InputStream getInputStream():获取文件流
-
void transferTo(File dest):将上传文件保存到一个目录文件中
我们去实际测试一下
3、编写前端页面
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
4、Controller
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}
5、测试上传文件,OK!
采用file.Transto 来保存上传的文件
1、编写Controller
/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:"+realPath);
//通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
2、前端表单提交地址修改
3、访问提交测试,OK!
文件下载
文件下载步骤:
1、设置 response 响应头
2、读取文件 -- InputStream
3、写出文件 -- OutputStream
4、执行操作
5、关闭流 (先开后关)
代码实现:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "基础语法.jpg";
//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
前端
<a href="/download">点击下载</a>
测试,文件下载OK,大家可以和我们之前学习的JavaWeb原生的方式对比一下,就可以知道这个便捷多了!