一、SpringMVC注解
1.1 常用注解
注解名 | 属性 | 作用范围 | 功能 |
---|---|---|---|
@Controller | value:指定控制器名字 | 在类上使用 | 用来标注该类是控制器 |
@RequestMapping | name:指定URL映射的名字 value:指定请求地址 path:指定请求的url method:指定请求方式 produces:指定响应内容的格式 | 可以在类上使用,也可以在方法上使用 | 指定请求的URL地址 |
@RequestParam | value:指定参数名 required:是否必须的 default:默认值 | 在形参中使用 | 指定请求参数名 |
@PathVariable | value:指定url中占位符的名字 | 在形参中使用 | 处理请求url中的占位符参数 |
@ResponseBody | 在方法上使用 | 指定返回值通过response对象输出到页面上 | |
@ModelAttribute | value:指定参数名 | 在形参中使用 | 从Model中获取数据,并绑定到指定参数 |
@SessionAttributes | names:把Model中指定属性绑定到Session中 types:把Model中指定类型的属性绑定到session | 在类上使用 | 把数据绑定到session |
1.2 使用注解
1.2.1 环境准备
(1)在src目录下新建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">
<!-- 启动注解功能 -->
<mvc:annotation-driven"/>
<!-- 启用包扫描功能 -->
<context:component-scan base-package="com.xjy.controller"/>
</beans>
(2)在web.xml中配置ContextLoaderListener;
<!-- Spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 加载Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
1.2.2 功能演示
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(path="/saveUser.do", method=RequestMethod.GET)
public ModelAndView saveUser(@RequestParam("userId") String id
, @RequestParam("userName") String name) throws Exception {
System.out.println("添加用户...");
System.out.println("用户编号:" + id);
System.out.println("用户名:" + name);
return new ModelAndView("main", "name", name);
}
@RequestMapping(path="/{id}/deleteUser.do", method=RequestMethod.GET
, produces="text/html;charset=utf-8")
@ResponseBody
public String deleteUser(@PathVariable("id") String id) throws Exception {
System.out.println("正在删除ID为" + id + "的用户...");
return "<h1>删除成功!</h1>";
}
}
二、中文乱码问题处理
提交表单数据的时候,浏览器会使用页面编码UTF-8进行编码,而服务器使用默认的字符集(iso-8859-1)进行解码。因为编码和解码使用了不同的字符集,才导致了获取的参数出现中文乱码的问题。
解决请求参数中文乱码的办法有以下两种:
2.1 手动处理
先使用iso-8859-1对出现中文乱码的参数进行编码,然后再使用utf-8对编码后的数据进行解码。
@RequestMapping("/addUser")
public void addUser(@RequestParam("userName")String name) {
try {
// 处理中文乱码
name = new String(name.getBytes("iso-8859-1"), "utf-8");
System.out.println("userName = " + name);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
2.2 全局处理
在web.xml文件配置CharacterEncodingFilter过滤器,并指定使用的编码格式。
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
三、请求路径的优先级
@Controller
public class HelloController {
@RequestMapping("/test.do")
@ResponseBody
public String test1() {
return "test1...";
}
@RequestMapping("/*.do")
@ResponseBody
public String test2() {
return "test2...";
}
@RequestMapping("/test*.do")
@ResponseBody
public String test3() {
return "test3...";
}
}
当访问Http://localhost:8080/test.do时候,匹配的顺序是:test1->test3->test2。而且,如果匹配成功,将不会再继续匹配。
四、修改配置文件的名字和存放路径
修改web.xml文件,然后在配置核心控制器节点中添加contextConfigLocation参数。
五、方法返回值
控制器方法可以返回不同类型的数据。除了ModelAndView类型以外,还可以是String类型,代表视图名。例如:
如果返回的字符串以“redirect:/”开头,那么就代表请求重定向到目标资源。但是只能够重定向到该项目下的其他资源。
如果想重定向到站外资源,可以使用下面这种方式:
return new ModelAndView(new RedirectView("http://www.baidu.com"));
如果model中包含数据,那么这些数据就会添加到重定向URL的后面。
返回结果类型也可以是集合类型、void或null。如果返回结果是集合、void、null,那么请求路径的名字作为视图名被解析。
例如:http://localhost:8080/ssmtest/user/addUser.do,/ssmtest是上下文路径,/user/addUser.do是资源路径,那么对应的视图名为user/addUser。
六、日期类型处理
如果表单提交过来的数据是日期格式,但是控制器使用Date类型接收该参数参数,这时候就会提示类型转换失败。
- 解决办法:
(1)使用@DateTimeFormat指定转换格式
(2)控制器中加入一段数据绑定代码。
每次访问该控制器方法的时候都会执行@InitBinder绑定的方法。
(3)配置全局日期类型转换器。
首先,定义一个日期转换器类,该类实现Converter接口。
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
然后,在配置文件中进行配置。
七、异常处理
在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。因此,我们需要统一进行异常处理。
下面介绍异常处理的三种方式。
7.1 使用自带的异常处理器
<!-- 配置异常处理器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--
配置默认错误处理页
value:视图的名称
-->
<property name="defaultErrorView" value="global-error"/>
<!-- 对指定异常类型进行处理 -->
<property name="exceptionMappings">
<props>
<!-- key代表异常类型,value代表视图名 -->
<prop key="java.lang.RuntimeException">error</prop>
</props>
</property>
</bean>
7.2 自定义异常处理类
首先,创建一个异常处理类。
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "服务器发生异常,请稍后再试!");
mv.setViewName("error");
//输出异常的跟踪信息
ex.printStackTrace();
return mv;
}
}
然后在配置文件中配置该异常处理类。
<bean class="包名.MyExceptionHandler"/>
7.3 使用@ExceptionHandler注解
在控制器类中定义一个异常处理的方法,并且使用@ExceptionHandler注解标注该方法。
@ExceptionHandler
public String handleExcpetion(HttpServletRequest request, Exception ex) {
if (ex instanceof java.lang.RuntimeException) {
return "error";
} else {
return "global-error";
}
}
该方法有两个参数:
request:当前发生异常的请求;
ex:异常对象;
八、文件上传
8.1 环境准备
第一步:定义文件上传表单;
<form action="${pageContext.request.contextPath}/upload.do" method="post"
enctype="multipart/form-data">
用户名:<input type="text" name="userName"/><br/>
大头照:<input type="file" name="pic"/><br/>
<input type="submit" value="提交"/>
</form>
第二步:引入文件上传的jar包;
第三步:配置文件上传解析器;
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件上传的大小 -->
<property name="maxUploadSize" value="10240"/>
</bean>
8.2 后台实现
SpringMVC是使用MultipartFile类实现文件上传。MultipartFile代表上传的文件。
@RequestMapping(value="/upload.do")
public ModelAndView upload(HttpServletRequest request
, @RequestParam(value="pic", required=true) MultipartFile file
, User user) throws Exception {
//获取保存文件的真实路径
String savePath = request.getServletContext().getRealPath("/uploads");
//获取上传的文件名
String fileName = file.getOriginalFilename();
//创建File对象
File targetFile = new File(savePath, fileName);
//保存文件
file.transferTo(targetFile);
//把上传文件的URL保存到Model中
ModelAndView mv = new ModelAndView();
mv.addObject("picUrl", "/uploads/" + fileName);
mv.setViewName("success");
return mv;
}
九、文件下载
第一步:创建文件下载页面。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download.do?fileName=3.jpg">下载图片..</a>
</body>
</html>
第二步:定义一个控制器类,实现文件下载。
@Controller
public class DownloadController {
@RequestMapping(value="/download.do")
public void download(HttpServletRequest request
, HttpServletResponse response, String fileName) throws Exception {
//设置响应头
response.setHeader("Content-Disposition", "attachement;filename=" + fileName);
//获取文件上传路径
String path = request.getServletContext().getRealPath("/uploads");
//创建File对象
File file = new File(path, fileName);
//读取文件
FileInputStream fis = new FileInputStream(file);
//创建文件输出流对象
OutputStream os = response.getOutputStream();
int len = -1;
byte[] buf = new byte[1024];
while ((len = fis.read(buf)) != -1) {
os.write(buf, 0, len);
}
//关闭资源
fis.close();
}
}