SpringMVC 概述
SpringMVC 是什么
- 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。
- Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供
了构建 Web 应用程序的全功能 MVC 模块。 - 使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的
SpringMVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等。
SpringMVC 在三层架构的位置
SpringMVC 的优势
1、清晰的角色划分:
- 前端控制器(DispatcherServlet)
- 请求到处理器映射(HandlerMapping)
- 处理器适配器(HandlerAdapter)
- 视图解析器(ViewResolver)
- 处理器或页面控制器(Controller)
- 验证器(Validator)
- 命令对象(Command 请求参数绑定到的对象就叫命令对象)
- 表单对象(Form Object提供给表单展示和提交到的对象就叫表单对象
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
3、由于命令对象就是一个POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。
7、功能强大的数据验证、格式化、绑定机制。
8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的 JSP 标签库,使 JSP 编写更容易。
………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配 置支持等等
SpringMVC 和 Struts2 的优略分析
共同点: 它们都是表现层框架,都是基于 MVC 模型编写的。 它们的底层都离不开原始 ServletAPI。
它们处理请求的机制都是一个核心控制器。
区别:
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
Spring MVC 是基于方法设计的,而Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所 以 Spring MVC 会稍微比 Struts2 快些。
Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便 (JSR303 是一套 JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注 解加在我们 JavaBean的属性上面,就可以在需要校验的时候进行校验了)
Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC更高些,但执行效率并没有比 JSTL 提 升,尤其是 struts2 的表单标签,远没有 html 执行效率高。
SpringMVC入门
快速入门
- 创建WEB骨架的Maven工程
为了解决Maven项目创建过慢(每次都从中央仓库下载),可以添加一行
key: archetypeCatalog
value:internal
- 配置Tomcat,补全遗漏的文件(java,resources)
- 配置依赖坐标
<!-- 版本锁定 -->
<properties>
<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>
- 创建前端控制器(servlet)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--用于让该servlet一初始化,就读取SpringMvc配置文件-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMvc.xml</param-value>
</init-param>
<!--服务器一开启,该servlet就被创建-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 创建控制器类
/*
* 该类是一个控制器类
* */
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String sayHello(){
System.out.println("HelloController");
return "success";
}
}
- 创建SpringMVC的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!--配置spring容器创建时要扫描的包-->
<context:component-scan base-package="controller"></context:component-scan>
<!--开启springMVC的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--视图解析器-->
<bean id="viewController" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前端控制器会将数据发送到 WEB-INF下的xxx.jsp中-->
<property name="prefix" value="WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
运行原理
当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件
开启了注解扫描,那么HelloController对象就会被创建
从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解,找到执行的具体方法
根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
Tomcat服务器渲染页面,做出响应
入门案例中的组件分析
- 前端控制器(DispatcherServlet)
- 处理器映射器(HandlerMapping)
- 处理器(Handler)
- 处理器适配器(HandlAdapter)
- 视图解析器(View Resolver)
- 视图(View)
< mvc:annotation-driven >说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器) 和RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中, 使 用mvc:annotation-driven替代注解处理器和适配器的配置
RequestMapping注解
- RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
- RequestMapping注解可以作用在方法和类上
- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- 细节:路径可以不编写 / 表示应用的根目录开始
- 细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
- RequestMapping的属性
- path 指定请求路径的url
- value value属性和path属性是一样的
- mthod 指定该方法的请求方式
- params 用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
例如:
params = {“accountName”},表示请求参数必须有 accountName
params = {“moeny!100”},表示请求参数中 money 不能是 100。 - headers 发送的请求中必须包含的请求头
- 以上四个属性只要出现 2 个或以上时,他们的关系是与的关系
请求参数绑定
1、绑定机制
- 表单提交的数据都是k=v格式的 username=haha&password=123
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
<a href="account/findAccount?accountId=10">查询账户</a>
@RequestMapping("/findAccount")
//自动绑定accountId参数
public String findAccount(Integer accountId) {
System.out.println("查询了账户。。。。"+accountId);
return "success"; }
2、支持的数据类型
- 基本类型参数:包括基本类型和 String 类型
- POJO 类型参数:包括实体类,以及关联的实体类
- 数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)
注意:
- 当参数类型为POJO,提交表单的name和JavaBean中的属性名称需要一致; 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:user.name
<form action="/params" method="post">
姓名:<input type="text" name="name">
余额:<input type="text" name="money">
用户姓名:<input type="text" name="user.name">
用户年龄:<input type="text" name="user.age">
<input type="submit" value="提交">
</form>
- 当参数类型为集合类型时
<form action="/params" method="post">
姓名:<input type="text" name="name">
余额:<input type="text" name="money">
用户姓名:<input type="text" name="list[0].name">
用户年龄:<input type="text" name="list[0].age">
用户姓名:<input type="text" name="map['one'].name">
用户年龄:<input type="text" name="map['one'].age">
<input type="submit" value="提交">
</form>
请求参数解决中文乱码问题
在web.xml中配置Spring提供的过滤器类
<!--配置编码过滤器-->
<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>
自定义类型转换器
使用步骤
- 自定义转换器类,实现Converter接口
public class DIYConverter implements Converter<String, Date> {
@Override
//自定义转换器,将String类型转为Date类型
public Date convert(String source) {
if (source == null) {
throw new RuntimeException("参数为null");
}else{
try {
DateFormat df=new SimpleDateFormat("yyyy-MM-dd");
//若String类型格式符合规则,转换成Date对象
Date date = df.parse(source);
return date;
} catch (ParseException e) {
e.printStackTrace();
throw new RuntimeException("转换异常");
}
}
}
}
- 配置自定义转换器
<!--自定义转换器,将我们自定义的转换器类,添加到spring的转换器中-->
<bean id="converter" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="converter.DIYConverter"></bean>
</set>
</property>
</bean>
- 开启自定义转换器
<!--开启springMVC的支持,并且使自定义转换器生效-->
<mvc:annotation-driven conversion-service="converter"></mvc:annotation-driven>
获取原生ServletAPI
直接在方法参数上添加Http请求,Http响应即可
public void getAPI(HttpServletRequest req, HttpServletResponse resp){
HttpSession session = req.getSession();
ServletContext servletContext = session.getServletContext();
System.out.println(req);
System.out.println(session);
System.out.println(resp);
System.out.println(servletContext);
}
常用注解
RequestParam
- 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
- 属性
- value:请求参数中的名称
- required:请求参数中是否必须提供此参数,默认值是true,为必须提供此参数,且名称必须一致
- 例如
@RequestMapping(“reqParam”)
public void requestParam(@RequestParam(“name”) String username){
System.out.println(username);
}RequestBody
作用:用于获取请求体的内容(注意:get方法不可以)
属性
- required:是否必须有请求体,默认值是true‘
例如
@RequestMapping(“reqBody”)
public void requestBody(@RequestBody String body){
System.out.println(body);
}PathVariable注解
- 作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
- 属性
- value:指定url中的占位符名称
- 例如
@RequestMapping(“pathVariable/{sid}”)
//将占位符的sid的值,赋值给形参id
public void pathVariable(@PathVariable(“sid”) String id){
System.out.println(id);
}- Restful风格的URL
- 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
- restful风格的URL优点
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
RequestHeader注解
- 作用:获取指定请求头的值
- 属性
- value:请求头的名称
- 例如
@RequestMapping(“requestHeader”)
public void requestHeader(@RequestHeader(“accept”) String header){
System.out.println(header);
}CookieValue注解
- 作用:用于获取指定cookie的名称的值
- 属性
- value:cookie的名称
- 例如
@RequestMapping(“cookieValue”)
public void cookieValue (@CookieValue(“JSESSIONID”) String cookie){
System.out.println(cookie);
}ModelAttribute注解
- 作用
- 出现在方法上:表示当前方法会在控制器方法执行前先执行。
- 出现在参数上:获取指定的数据给参数赋值。
- 应用场景
当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据SessionAttributes注解
- 作用:用于多次执行控制器方法间的参数共享,只能作用于类上
- 属性
- value:指定存入属性的名称
ModelAttribute注解示例
/*
* @ModelAttribute
* 先于控制器方法前执行,作用于方法或者参数上
* 1. 出现在方法上:表示当前方法会在控制器方法执行前先执行。
* 2. 出现在参数上:获取指定的数据给参数赋值。
* */
@RequestMapping("modelAttribute")
public void modelAttribute(@ModelAttribute("user1") User user) {
System.out.println(user);
}
/*
* 先于控制器方法执行,获取到传递的参数,手动封装user,返回user对象
* 控制器方法执行时,获取到该user对象
* */
@ModelAttribute
public User completeUser(String name, Integer age) {
User user = new User();
user.setId(1);
user.setAge(age);
user.setName(name);
return user;
}
/*
* 先于控制器方法执行,获取到传递的参数,手动封装user,存入Map集合,无返回值
* 控制器方法执行时,使用@ModelAttribute注解,获取Map集合中的数据
* */
@ModelAttribute
public void completeUser(String name, Integer age, Map<String, User> map) {
User user = new User();
user.setId(2);
user.setAge(age);
user.setName(name);
map.put("user1",user);
}
SessionAttributes注解示例
/*
* 设置请求对象中参数
* @SessionAttributes注解设置到类上,可以将请求参数添加到session中
* */
@RequestMapping("setSession")
public void setRequest(ModelMap model) {
//相当于request.setAttribute()
model.addAttribute("msg", "请求信息");
}
/*
* 获取session中的参数
* */
@RequestMapping("getSession")
public void getSession(ModelMap model) {
String msg = (String) model.get("msg");
System.out.println(msg);
}
/*
* 删除session中的参数
* */
@RequestMapping("delSession")
public void delSession(SessionStatus status){
status.setComplete();
}
响应数据和结果视图
返回值分类
- 返回字符串
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
/*
* 返回值为String
* 视图解析器会自动帮助查找页面
* */
@RequestMapping("/testString")
public String testString(ModelMap modelMap){
//模拟从数据库获取数据,并转发给jsp页面过程
User user=new User();
user.setId(1);
user.setName("maki");
user.setMoney(1000);
modelMap.addAttribute("user",user);
//根据视图解析器,查找页面
return "success";
}
- 返回值是void
- 默认会跳转到@RequestMapping("/xxx") xxx的页面
- 可以使用请求转发或者重定向跳转到指定的页面
- 注意:请求转发和重定向,不再使用视图解析器
/*
* 返回值为void
* 默认情况会找,请求映射中的文件地址 例如:xxx/xxx/testVoid.jsp
* 可以手动编写请求转发,重定向
* */
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest req, HttpServletResponse resp) throws Exception{
//模拟从数据库获取数据,并转发给jsp页面过程
User user=new User();
user.setId(2);
user.setName("maki");
user.setMoney(2313);
/* //请求转发
req.setAttribute("user",user);
req.getRequestDispatcher("pages/success.jsp").forward(req,resp);*/
//重定向
resp.sendRedirect(req.getContextPath()+"pages/success.jsp");
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().println("hello");
return;
}
}
- 返回值是ModelAndView对象
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
/*
* 返回值为ModelAndView对象
* 其实就是返回值为String的另一种写法格式
* */
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
ModelAndView mv=new ModelAndView();
//模拟从数据库获取数据,并转发给jsp页面过程
User user=new User();
user.setId(4);
user.setName("yui");
user.setMoney(2333);
//相当于modelMap.addAttribute("user",user);
mv.addObject("user",user);
//相当于 return "success";
mv.setViewName("success");
return mv;
}
- 使用关键字请求转发/重定向
/*
* 使用关键字进行请求转发和重定向
* */
@RequestMapping("testForwardOrRedirect")
public String testForwardOrRedirect(){
//请求转发
//return "forward:/pages/success.jsp";
//请求重定向,spring框架自动在路径上添加了全项目名
return "redirect:index.jsp";
}
ResponseBody响应异步请求
静态资源不拦截
- DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源
(img、css、js)也会被拦截到,从而不能被使用。 - 解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
mvc:resources标签配置不过滤
location元素表示webapp目录下的包下的所有文件
mapping元素表示以/xxx开头的所有请求路径,如/xxx/a 或者/xxx/a/b
<!--告知前端控制器,静态资源不拦截-->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
导入依赖坐标
json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
<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>
发送异步请求
发送一个json数据类型的异步请求
<script src="js/jquery-3.3.1.min.js"></script>
<script>
//页面加载,绑定单击事件
$(function (){
$("#bt").click(function () {
//发送异步请求
$.ajax({
url:"testAjax", //请求url
contentType:"application/json;charset=utf-8", //请求头信息,表示mime类型和字符集
data:'{"name":"maki","money":"2000","id":"3"}', //请求体内容(发送给服务器端的数据)
dataType:"json", //请求体内容的数据格式
type:"post", //请求方式
success:function (data) { //回调函数,响应成功后执行
//data表示服务器端响应的json数据
//有了jackson的坐标,spring会自动将javaBean转为json
alert(data.name);
alert(data.money);
alert(data.id);
}
});
});
});
</script>
接收并响应异步请求
/*
* 有了jackson坐标,spring会自动将请求体中的json数据转为javaBean
* 使用@ResponseBody注解
* spring会自动将javaBean转为json,传给回调函数
* */
@RequestMapping("testAjax")
public @ResponseBody User testAjax(@RequestBody User jsonData){
System.out.println(jsonData);
jsonData.setName("yui");
jsonData.setId(2);
jsonData.setMoney(2333);
return jsonData;
}
文件上传
文件上传的必要前提
- form 表单的 enctype 取值必须是:multipart/form-data
(默认值是:application/x-www-form-urlencoded)
enctype:是表单请求正文的类型 - method 属性取值必须是 Post
- 提供一个文件选择域< input type=”file” />
文件上传的原理分析
当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
key=value&key=value&key=value
当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成:
每一部分都是 MIME 类型描述的正文
----------------------------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name=“userName” 协议头
-----------------------------7de1a433602ac
Content-Disposition: form-data; name=“file”; 协议的正文
filename=“C:\Users\zhy\Desktop\fileupload_demofile\b.txt”
Content-Type: text/plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac–
借助第三方组件实现文件上传
使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。
commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。
依赖坐标
<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>
原始的上传方法
@RequestMapping("befUpload")
public String befUpload(HttpServletRequest req) throws Exception {
//先获取到要上传的文件目录
String realPath = req.getSession().getServletContext().getRealPath("/uploads");
System.out.println(realPath);
//创建File对象,一会向该路径下上传文件
File file = new File(realPath);
if (!file.exists()) {
//若文件不存在,创建文件
file.mkdirs();
}
//创建磁盘文件项工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request对象
List<FileItem> items = upload.parseRequest(req);
for (FileItem item : items) {
//判断文件项是普通字段,还是上传字段
if (item.isFormField()) {
} else {
//获取到上传文件的名称
String filename = item.getName();
//上传文件
item.write(new File(file, filename));
//删除临时文件
item.delete();
}
}
return "success";
}
SpringMVC上传原理
SpringMVC上传方法
- 上传页面
<%-- SpringMvc上传文件操作,由前端控制器将请求体内容,发给文件解析器,获取到表单中的上传项,自动绑定到方法的形参上(形参名必须等于表单项的name值)--%>
<h3>SpringMVC文件上传方式</h3>
<form action="/mvcUpload" method="post" enctype="multipart/form-data" >
<input type="file" value="选择文件" name="upload">
<input type="submit" value="提交">
</form>
- 配置一个文件解析器(需要jar包支持)
<!--
文件解析器,用来解析表单中的上传文件项
id值为固定写法
可以设置一些参数,例如:限制文件上传大小
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
- 控制器中的方法
/*
* SpringMVC方式实现文件上传
* 形参必须与input文件上传标签的name属性值一样,才能自动绑定
* */
@RequestMapping("mvcUpload")
public String mvcUpload(HttpServletRequest req,MultipartFile upload) throws IOException {
//获取要上传的文件目录
String realPath = req.getSession().getServletContext().getRealPath("uploads");
System.out.println(realPath);
//创建File对象,一会向该文件目录下上传文件
File file=new File(realPath);
if(!file.exists()){
file.mkdirs();
}
//获取上传文件项的文件名
String uploadName = upload.getOriginalFilename();
System.out.println(uploadName);
//上传文件
upload.transferTo(new File(file,uploadName));
return "success";
}
SpringMVC跨平台服务器上传
- 搭建一个新的服务器
- 导入开发需要的jar包
<!--用于使用spring MVC方式实现跨平台服务器上传-->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
- 上传页面
<%-- SpringMVC跨服务器上传--%>
<h3>SpringMVC跨服务器上传</h3>
<form action="/acrossServiceUpload" method="post" enctype="multipart/form-data" >
<input type="file" value="选择文件" name="upload">
<input type="submit" value="提交">
</form>
- 同样需要文件解析器
<!--
文件解析器,用来解析表单中的上传文件项
id值为固定写法
可以设置一些参数,例如:限制文件上传大小
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
- 后台代码
/*
* SpringMVC方式实现跨服务器上传
* 形参必须与input文件上传标签的name属性值一样,才能自动绑定
* */
@RequestMapping("acrossServiceUpload")
public String acrossServiceUpload(MultipartFile upload) throws IOException {
//获取要上传的服务器中的路径
String path="http:localhost:9090/uploads/";
//获取上传文件项的文件名
String uploadName = upload.getOriginalFilename();
System.out.println(uploadName);
//向另一个服务器上传文件
//1. 创建客户端对象
Client client = Client.create();
//2. 连接另一个服务器
WebResource resource = client.resource(path+uploadName);
//3. 上传文件
resource.put(upload.getBytes());
return "success";
}
SpringMVC中的异常处理
异常处理原理分析
实现步骤
- 编写自定义异常类
public class MyException extends Exception{
//异常提示信息
private String message;
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public MyException(String message) {
this.message = message;
}
}
- 编写自定义的异常处理器(实现HandlerExceptionResolver接口)
public class MyExceptionResolver implements HandlerExceptionResolver {
/*
* 当前端控制器接收到异常信息时,会跳转到异常处理器来解决(需要先注册该处理器)
* 跳转到具体的错误页面的方法
* */
public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object o, Exception e) {
ModelAndView mv=new ModelAndView();
MyException myexc=null;
//若接收到的异常信息属于我们自定义的异常类,强转
if(e instanceof MyException){
myexc=(MyException)e;
}else{
//若接收到的异常信息不属于自定义的异常类,设置一个新的异常信息
myexc=new MyException("服务器维护中...");
}
//存入异常信息
mv.addObject("errorMsg",myexc.getMessage());
//跳转错误页面
mv.setViewName("error");
return mv;
}
}
- 配置异常处理器
<!--注册异常处理器-->
<bean id="exceptionResolver" class="exception.MyExceptionResolver"></bean>
SpringMVC中的拦截器
- 拦截器的概述
SpringMVC框架中的拦截器用于对Controller中的方法进行预处理和后处理的技术。 - 可以定义拦截器链,就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
- 拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
- 拦截器也是AOP思想的一种实现方式
- 想要自定义拦截器,需要实现HandlerInterceptor接口。
自定义拦截器步骤
- 创建类,实现HandlerInterceptor接口,重写需要的方法
public class MyInterceptor implements HandlerInterceptor {
/*
* 控制器中方法执行前,先执行
* 返回值:true-放行 false-不放行
* */
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器在方法执行前...........执行了");
return true;
}
/*
* 控制器中方法执行后,跳转页面前,先执行
* */
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器在方法执行后,跳转页面前...........执行了");
}
/*
* 控制器中方法执行后,跳转页面后,再执行
* */
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器在方法执行后,跳转页面后...........执行了");
}
}
- 在springmvc.xml中配置拦截器类
<!--配置拦截器们-->
<mvc:interceptors>
<!--配置拦截器,若有多个拦截器,需要写多个该标签-->
<mvc:interceptor>
<!--那些方法进行拦截-->
<mvc:mapping path="/*"/>
<!--哪些方法不拦截-->
<mvc:exclude-mapping path="/find*"/>
<!--注册拦截器对象-->
<bean class="interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
HandlerInterceptor接口中的方法
- preHandle方法是controller方法执行前拦截的方法
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
- postHandle是controller方法执行后执行的方法,在JSP视图执行前。
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
- postHandle方法是在JSP执行后执行
- request或者response不能再跳转页面了