第一天
三层架构
SpringMvc概述
Spring的入门程序
入门案例中使用的组件介绍(特别重要)
RequestMapping注解的作用
请求参数的绑定(特别重要)
过滤器解决中文乱码
自定义类型转换器
获取Servlet原生的API
常用注解
第二天
响应数据和结果视图
Response响应json数据
SpringMvc文件上传
SpringMvc的异常处理
SpringMvc中的拦截器
三层架构
MVC模式:
SpringMvc概述
SpringMvc在三层架构中的位置
SpringMVC的优势
SpringMvc和Struct2的优略分析
Spring入门程序
入门程序的需求:
1、搭建环境
用骨架来构建:
进去之后我们发现结构是这样的,没有java和resources文件
所以我们要自己创建java和resources文件。
2、导入依赖
这里将版本改成1.8
然后再将spring的版本控制成5.0.2
然后再导入依赖:
<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>
<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>
创建spring配置文件,导入协议
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
部署tomcat
入门程序代码编写
默认的index.jsp文件中没有文件头,所以需要将默认的index.jsp文件删除后重新创建一个index.jsp,创建一个超链接
创建一个Controller类
用@Controller注解将controller类创建到容器中,在方法上使用@RequestMapping注解,作用其实和servlet是差不多的,这样在jsp文件中就能用@RequestMapping的path属性使用被映射的方法。(注意:这里的斜杠不能省略)
所以这时我们就要配置注解扫描
在springmvc中加入标签
<context:component-scan base-package="cn.itcast"></context:component-scan>
但是需要注意的是,虽然我们配置了这个文件,但是这个文件从来没有被加载过,那里面的配置也就一点作用都不起。
所以这又回到了前端控制器中,让前端控制器帮我们加载。
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
在里面加入<init-param>
这个标签,表示给DispatcherServlet类的contextConfigLocation这个属性配置了classpath:springmvc.xml这个值。意思就是在创建DispatcherServlet类的时候,DispatcherServlet就会帮我们加载classpath:springmvc.xml这个路径下的文件。而DispatcherServlet是一个servlet,servlet是什么时候创建的,是在第一次客户端发送请求的时候创建的,而配置的<load-on-startup>1</load-on-startup>
表示在创建服务器的时候就创建DispatcherServlet这个对象,也就会加载springmvc这个文件。
跳转成功页面
在WEB-INF/pages/success.jsp创建成功页面。现在我们想从sayHello()这个方法跳回到这个页面,就需要用到一个叫做视图解析器的组件。
配置视图解析器
在springmvc.xml中配置
<!-- 视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property><!-- 配置前缀 -->
<property name="suffix" value=".jsp"></property>
</bean><!-- 配置后缀 -->
也就是当我们的RequsetMapping注解的方法返回一个"success"的字符串,前端控制器就会去找/WEB-INF/pages里的success.jsp文件
最后,开启spring框架注解的支持
<!-- 开启SpringMvc框架注解的支持 -->
<mvc:annotation-driven conversion-service="ConversionService"/>
最后将所有的配置全都统一看一遍:
web.xml:
springmvc:
controller类
index.jsp(注意:这里的hello不能加/)
success.jsp
入门程序的流程总结:
入门案例中使用的组件介绍
***这张图片是SpringMvc的流程图,非常重要。***
可以看到spring主要有3个组件,但是前面我们只配置了前端控制器和视图解析器,那处理器适配器难道我们就没打开吗?不对!
RequestMapping注解的作用
作用:用于建立请求url和处理请求方法之间的关系
我们进去RequestMapping注解的源码:
发现它既可以用在方法上,也可以用在类上。
举个例子:
我们在类上加一个@RequestMapping("/user")
这样的话在index.jsp就要改变成<a href="user/hello">入门程序</a>
也就是说在类上加@RequestMapping注解其实是起到分模块的作用,以后我们有accountController,userController,就可以用account/*
和user/*
来区分,让开发更清晰,但是需要注意的是,第一级目录的前面一定不能加斜杠
@RequestMapping注解的属性:
1、path和value
可以发现path和value属性的别名互相是对方,也就是所path和value的作用是一样的,并且在只写path或者value的情况下,可以不用写属性名:@RequestMapping("/user")
2、method
我们看到method属性是一个RequestMethod数组,点进去一看发现RequestMethod是一个枚举类型,也就是说可以直接用。
method的作用是指定请求方式。@RequestMapping(path = "/hello", method = {RequestMethod.POST})
这里的意思就是只有post方法能访问到这个方法。
3、params
我们看到params是一个字符串数组,它的意思是,要想访问这个方法就必须给方法传params里所有的属性。@RequestMapping(path = "/hello", params = {"username"})
这个的意思是必须要传一个名为username的属性。那就要这样<a href="user/hello?username=hehe">入门程序</a>
才能访问到。而当我这样设置@RequestMapping(path = "/hello", params = {"username=heiheihei"})
就意味着你不仅要给我传一个username的属性,这个属性的值还必须得是heihei,不然就无法访问。
4、headers
意思是发送的请求中必须包含的请求头@RequestMapping(path = "/hello", params = {"username=heiheihei"},headers = {"accept"})
请求参数的绑定
之前在使用servlet的时候,我们要想拿到请求的参数,都要使用request.getParameter()
这个方法来获取参数值,这样会比较麻烦。所以在springmvc中已经帮我们简便里这个,就叫做参数绑定。
它的实现方式很简单。比如现在有一个请求传了这样一些参数:username=hehe&password=123
,然后有这样一个方法:sayHello(String username, String password)
那么当这个请求到这个方法上时,springmvc就会帮我们把参数直接传到方法的username和password中,但是要注意,他们的参数名字必须一样,springmvc支持基本数据类型和字符串类型,JavaBean和集合
1、基本类型和字符串类型:
建立超链接:<a href="param/testParam?username=hehe&password=123">请求参数绑定</a>
建立Controller类:
2、JavaBean
先建立实体类:
这里需要注意,实体类属性的注入依靠的是set方法,如果没有set方法将无法注入
编写jsp文件:
当实体类中还有其他的JavaBean,就写成这个JavaBean的名字+. +属性名,如上图所示。
3、集合类型
创建集合属性:
编写jsp文件
<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="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/>
<input type="submit" value="提交" />
</form>
过滤器解决中文乱码
在上面的参数绑定中,我们都没有输入过中文,如果我们输入中文试试,控制台就会出现下图这样乱码的情况。
之前我们的解决办法是:request.setCharacterEncoding("UTF-8");
,但是在每一个方法前面都加这个太麻烦了。这里SpringMvc给我们提供了一个过滤器。
在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>
这里<url-pattern>
里的/*
表示拦截所有请求
自定义类型转换器
因为页面提交的任何数据都是字符串,但是在上面的参数绑定中,依然可以绑定到Integer类型,这是因为springmvc框架已经为我们自动进行了数据转换。但是对于日期类型,有2000/11/11
的,也有2000-11-11
的,由于有太多的格式,这个springmvc没办法为我们转换了,这样就用到了自定义类型转换器。
我们进入Converter的类看看他的实现类
可以看到有很多的类型转换,比如我箭头指示的string变成number的方法。
先创建一个类,让这个类实现Converter接口,并且以<String,Data>形式编写好,再引入需要实现的方法。
编写这个类,实现String到Data的方法。
public class StringToDateConverter implements Converter<String,Date>{
/**
* String source 传入进来字符串
* @param source
* @return
*/
public Date convert(String source) {
// 判断
if(source == null){
throw new RuntimeException("请您传入数据");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
// 把字符串转换日期
return df.parse(source);
} catch (Exception e) {
throw new RuntimeException("数据类型转换出现错误");
}
}
}
配置自定义类型转换器
在springmvc中配置,这里的set里面的<bean>
标签里就放我们刚刚写的实现类。这里的作用是加入我们实现的这个类,它原本的那些实现类依然存在
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"/>
</set>
</property>
</bean>
获取Servlet原生的API
直接在方法的参数上加入request或者response就行了。
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
System.out.println("执行了...");
System.out.println(request);
HttpSession session = request.getSession();
System.out.println(session);
ServletContext servletContext = session.getServletContext();
System.out.println(servletContext);
System.out.println(response);
return "success";
}
常用注解
@RequestParam
在前面的参数绑定中,我们要方法的参数和请求的参数名必须保持一致,并且区分大小写。这个注解就是解决参数名不一样的情况。
我们进入这个注解的源码:
这里的required表示了必须,并且默认是true。意思就是,看下图,我这样配置了,你就必须给我传一个name的属性,哪怕是uname都不行,不传也不行。
public String testRequestParam(@RequestParam(name="name") String username){
System.out.println("执行了...");
System.out.println(username);
return "success";
}
只需要在参数名前加入@RequestParam
就行,里面的参数值指定了请求中的属性名。
@RequestBody
这个注解蛮重要的,在后面的异步请求中用处很大。只需要在方法的参数前面加上就行了
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了...");
System.out.println(body);
return "success";
}
PathVaribale
@PathVaribale 这个注解主要是用于REST风格URL,也就是Restful风格。在原来的方式中,我们用不同的@RequestMapping的path来找到不同的方法。而在restful风格中,path都是一样的,首先它会以提交的不同方式来分类,比如get就会去找get,如果找到有多个get方法的,就会用后面的url占位符来确定。比如下面的,用user能找到findAll和findById两种,但是在url中加入10,就会指定到findById这个方法。
这个注释用起来很简单,在参数前直接加就行了,然后再@RequestMapping中加入占位符,这样@PathVariable就能读到占位符里的数据然后传给参数。注意:@PathVariable的name必须和@RequestMapping里的占位符名字一样。
<a href="anno/testPathVariable/10">testPathVariable</a>
@HiddenHttpMethodFilter
就是一个模拟提交方式的一个组件
@RequestHeader
用处不大,不具体说明,直接在参数前面加就行了
这样可以获得accept的消息头。
@CookieValue
这个也用的比较少
@ModelAttribute
作用在方法上时,会在控制器的方法执行前先执行它。
有两种情况。一种有返回值,一种没有返回值。
有返回值的情况:
jsp文件:
<form action="anno/testModelAttribute" method="post">
用户姓名:<input type="text" name="uname" /><br/>
用户年龄:<input type="text" name="age" /><br/>
<input type="submit" value="提交" />
</form>
Controller类
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(@ModelAttribute("abc") User user){
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
@ModelAttribute
public User showUser(String uname){
System.out.println("showUser执行了...");
// 通过用户查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
return user;
}
也就是在执行testModelAttribute方法执行,先执行了showUser,然后返回了一个user对象,这个user对象会传给testModelAttribute的参数。
没有返回值的情况:
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(@ModelAttribute("abc") User user){
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
@ModelAttribute
public void showUser(String uname, Map<String,User> map){
System.out.println("showUser执行了...");
// 通过用户查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
map.put("abc",user);
}
需要在showUser的参数中加入一个map集合,然后把返回值传入map中。testModelAttribute再直接从@ModelAttribute注解的中,取出key为value的对象赋值给参数。
SessionAttribute巨重要
当我们想从方法中向request的域对象存一些值,然后再在jsp文件中拿出来。以前的方法是创建一个HttpServletRequest request
对象,然后用request.setAttribute();
这个方法存值。现在我们用一个叫Model的接口,它的实现类是map,键值对的形式。当我们向Model中存键值对时,底层会把数据存入request的域对象中。
用法:
直接把model当成参数使用
@RequestMapping(value="/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes...");
// 底层会存储到request域对象中
model.addAttribute("msg","美美");
return "success";
}
jsp文件用EL表达式直接看值,sessionScope是session的全部内容
可以看到的确是存到了request的域对象中。
接下类我们看SessionAttributes注解:下图我们可以看到这个注解只能在类上使用。
在类上使用里这个注解后,会将model中以value为key的键值对都传到session里面去。注意:是从model中取值的,不是从request中,因为取值的时候,model中增加的数据还没加入到request中。
当我们想要从session中取出来值的时候,就需要用到ModelMap对象。
@RequestMapping(value="/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
System.out.println("getSessionAttributes...");
String msg = (String) modelMap.get("msg");
System.out.println(msg);
return "success";
}
当我们想要从session中删除对象时,就需要用到SessionStatus对象。
@RequestMapping(value="/delSessionAttributes")
public String delSessionAttributes(SessionStatus status){
System.out.println("getSessionAttributes...");
status.setComplete();
return "success";
}
响应数据和结果视图
返回值分类:
字符串(String)
字符串就是之前一直用来跳转"success"
这个界面的方法,不做过多解释。
无返回值(void)
没有返回值的方法,其实主要就是用请求转发和重定向,注意:重定向不能直接访问到WEB-INF文件夹里的内容,并且路径是不会被视图解析器扫描的,所以必须写全。
/**
* 是void
* 请求转发一次请求,不用编写项目的名称
*/
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("testVoid方法执行了...");
// 编写请求转发的程序
// request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
// 重定向
// response.sendRedirect(request.getContextPath()+"/index.jsp");
// 设置中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 直接会进行响应
response.getWriter().print("你好");
return;
}
然后还有一个直接响应的方法,直接在页面上显示“你好”两个字,不过这种方法用处不大。
ModelAndView
ModelAndView是SpringMvc提供的一个对象,可以用来调整具体的JSP视图。
其实这个对象就是字面意思一样,model和view,模型和视图
,就是既可以存javaBean对象,也可以存储向往哪个页面转,和上面Model效果其实是一样的,只是写法不一样。
我们进入这个对象看一下:发现里面也是个model对象,用的就是model对象的方法,也就是说当我们存数据进ModelAndView的时候,也会被存到request中。并且设置view的时候,这个view会经过视图解析器,所以可以直接写字符串形式。
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了...");
// 模拟从数据库中查询出User对象
User user = new User();
user.setUsername("小凤");
user.setPassword("456");
user.setAge(30);
// 把user对象存储到mv对象中,也会把user对象存入到request对象
mv.addObject("user",user);
mv.addObject("password","123");
// 跳转到哪个页面
mv.setViewName("success");
return mv;
}
上面的以字符串为返回值的方式,其实底层也是用ModelAndView的对象来实现的。
关键字
/**
* 使用关键字的方式进行转发或者重定向
* @return
*/
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect方法执行了...");
// 请求的转发
// return "forward:/WEB-INF/pages/success.jsp";
// 重定向
return "redirect:/index.jsp";
}
Response响应json数据
当我们想实现,前端传来一个ajax请求,然后我们要把数据打包成json传回去的情况。
先写一个button
按钮,然后给它绑定一个ajax请求。
首先,我们要导入JavaScript文件,然后打入以下代码:
<head>
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
alert("hello btn");
});
});
</script>
</head>
<body>
<button id="btn">发送ajax的请求</button>
</body>
但是运行的时候发现并没有因为alert
弹窗,这是什么问题呢。
这里我们看到引入了一个src="js/jquery.min.js"
的代码,但是由于前端控制器在设置的时候,用了/来拦截,这个静态文件也被拦截了,所以用不了src目录下的文件,以至于alert
也起不了作用。
解决办法,就是需要配置,让前端控制器不要拦截静态资源。
在springmvc.xml
中,加入以下代码:
<!--前端控制器,哪些静态资源不拦截-->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
css是样式文件,images是图片,js是JavaScript文件。以后都这个规范来写的话,这样配置就够了。注意:location里面不能带*号。
接下来,继续编写ajax请求:
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
// alert("hello btn");
// 发送ajax请求
$.ajax({
// 编写json格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",//指明编码方式为json
data:'{"username":"hehe","password":"123","age":30}',
dataType:"json",//指明传回的数据的类型是json类型
type:"post",
success:function(data){
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
alert(data.age);
}
});
});
});
</script>
然后编写Controller
@RequestMapping("/testAjax")
public void testAjax(@RequestBody String body){
System.out.println("testAjax方法执行了...");
System.out.println(body);
}
可以在控制台得到{"username":"hehe","password":"123","age":30}
,也就是传进来的data。
这里如果发过来的data的key值和JavaBean里的属性值是一样的,就能把value对应封装到JavaBean中,但是需要导入额外的3个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>
首先,我们把方法参数变成@RequestBody User user
,这里的user的属性值取跟data的key值相同,所以会自动帮我们把数据封装到user类中,这就完成了从json到实体类的转换,但是当我们返回的时候,返回的是user对象,可是在前面ajax的配置中,dataType
已经指明了要返回一个json的数据,这里就可以在返回值前面加一个@ResponseBody
的注解,它就会帮我们把user对象转换成json的数据:
/**
* 模拟异步请求响应
*/
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了...");
// 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
// 做响应,模拟查询数据库
user.setUsername("haha");
user.setAge(40);
// 做响应
return user;
}
SpringMvc文件上传
注意,这里在配置tomcat的时候,选项目的时候要选exploded
这里可以看到,当我们把form
表单的enctype
改成multipart/form-data
后,请求内容就被分成了几个区域,那这样我们怎么解析呢,这里就需要导入这两个jar包
<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>
1、传统文件上传:
我尝试的时候是传统上传方式一直不行,不过SpringMvc可以。找到原因了,回来记录,由于之前我在尝试传统文件上传的时候,已经配置了springmvc的文件解析器,这样当我在用传统文件上传的时候,参数里的request其实已经被springmvc解析过了,并且解析其实就是用的传统文件上传的方法,所以当我们再解析一次,肯定是为空,解决办法就是把文件解析器的配置给删掉,就能正常使用了。从这里得到答案:别人的详细分析
@RequestMapping("/fileupload1")
public String fileuoload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传...");
// 使用fileupload组件完成文件上传
// 上传的位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
System.out.println(path);
// 判断,该路径是否存在
File file = new File(path);
if(!file.exists()){
// 创建该文件夹
System.out.println("文件不存在,要创建");
file.mkdirs();
}
// 解析request对象,获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
// 解析request
List<FileItem> items = upload.parseRequest(request);
// 遍历
for(FileItem item:items){
System.out.println("66666");
// 进行判断,当前item对象是否是上传文件项
if(item.isFormField()){
// 说明普通表单向
}else{
// 说明上传文件项
// 获取上传文件的名称
String filename = item.getName();
// 把文件的名称设置唯一值,uuid
// String uuid = UUID.randomUUID().toString().replace("-", "");
// filename = uuid+"_"+filename;
// 完成文件上传
System.out.println(path);
item.write(new File(path,filename));
// 删除临时文件
item.delete();
}
}
return "success";
}
2、SpringMvc上传方式
执行方法:利用文件解析器来做中转站,直接拿到upload,然后通过参数绑定的方式赋值给方法的参数,所以名称必须一致。
配置文件解析器:
<!--配置文件解析器对象,要求id名称必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760" />
</bean>
这里的properties里面的maxUploadSize属性是上传的最大字节(Byte), 1KB = 1024Byte,1M=1024KB
/**
* SpringMVC文件上传
* @return
*/
@RequestMapping("/fileupload2")
public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("springmvc文件上传...");
// 使用fileupload组件完成文件上传
// 上传的位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
// 判断,该路径是否存在
File file = new File(path);
if(!file.exists()){
// 创建该文件夹
file.mkdirs();
}
// 说明上传文件项
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 完成文件上传
upload.transferTo(new File(path,filename));
return "success";
}
3、SpringMvc跨服务器的文件上传
这里需要导入额外的jar包
<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>
/**
* 跨服务器文件上传
* @return
*/
@RequestMapping("/fileupload3")
public String fileuoload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器文件上传...");
// 定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";
// 说明上传文件项
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 创建客户端的对象
Client client = Client.create();
// 和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
这个讲的很少,我也没成功,等以后作为一个专栏再学习一下吧,就贴个代码。
SpringMvc的异常处理
用异常处理器,来跳到指定的页面。
1、编写自定义异常类:
注意要继承Exception
public class SysException extends Exception{
// 存储提示信息的
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public SysException(String message) {
this.message = message;
}
}
2、编写异常处理器
注意要实现HandlerExceptionResolver
的接口
public class SysExceptionResolver implements HandlerExceptionResolver{
/**
* 处理异常业务逻辑
* @param request
* @param response
* @param handler
* @param ex
* @return
*/
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 获取到异常对象
SysException e = null;
if(ex instanceof SysException){
e = (SysException)ex;
}else{
e = new SysException("系统正在维护....");
}
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
3、配置异常处理器
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
SpringMvc中的拦截器
拦截器是AOP思想的具体实现
1、编写拦截器类
我们点进需要实现的HandlerInterceptor
看到,其实它已经把所有方法都默认实现过了,所以这里不是继承方法,而是重写方法,要从这里获取。
编写拦截器类的java代码
public class MyInterceptor1 implements HandlerInterceptor{
/**
* 预处理,controller方法执行前
* return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
* return false不放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...前1111");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法,controller方法执行后,success.jsp执行之前
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后1111");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
* success.jsp页面执行后,该方法会执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后1111");
}
}
2、配置拦截器
/**
代表拦截所有方法,/user/*
代表拦截/user/
下的方法。
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>
-->
<!--配置拦截器对象-->
<bean class="cn.itcast.interceptor.MyInterceptor1" />
</mvc:interceptor>
<!--配置第二个拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/**"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>
-->
<!--配置拦截器对象-->
<bean class="cn.itcast.interceptor.MyInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
结果,配置的两个拦截器完全按照上面的流程图来进行的,并且是按照从上到下的顺序来拦截的。
接下来就是ssm的整合了。