SpringMVC笔记
一、SpringMVC环境搭建及简单应用
1.springMVC.xml配置文件 选中常用的命名空间:beans aop context mvc。
2.通过以下配置,拦截所有请求交给SpringMVC处理。
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- spring入口 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- 如果不指定配置文件路径的话,可以把springmvc配置文件放在WEB-INF中,固定名称为
springDispatcherServlet-servlet.xml -->
<param-name>contextConfigLocation</param-name>
<param-value>classPath:springMVCProject.xml</param-value>
</init-param>
<!-- 项目启动自动生效 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 如果项目通过SpringMVC和Servlet同时管理,可以靠拦截器控制,这种说明只有以.action结尾的springmvc处理。
<url-pattern>.action</url-pattern>
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
3.在代码中可以指定用什么方式提交,默认提交是用get方式,下面可以改成用post方式提交。
@RequestMapping(value = "welcome", method = RequestMethod.POST)
4.前台传入到后端的数据,后端可以这样来接收:
其中value=前端name,required=false代表前台可以什么都不传递,defaultValue如果前台没有传递值过来,默认把里面的值放到id中。
@RequestMapping(value = "getPost" ,method = RequestMethod.POST)
public String getPost(@RequestParam(value="uname",required =false,defaultValue="123") Integer id){
System.out.println(id);
return "success";
}
5.前端将多个字段传到后端,后端用bean来接收,只需要前端和bean中定义的变量名一致即可获取到:
前端:
<form action="handler/testObject" name="student">
<input name="id" type="text"> <input name="name" type="text">
<input name="address.homeAddress" type="text">
<input name="address.schoolAddress" type="text">
<input type="submit" name="提交">
</form>
后端SpringMVC方式:
@RequestMapping(value = "testObject")
public String testObject(Student student) {
return "success";
}
后端servlet方式:
@RequestMapping(value = "testServletAPI")
public String testServletAPI(HttpServletRequest request) {
System.out.println(request.getParameter("name"));
return "success";
}
实体类(省略get、set方法):
public class Student {
private int id;
private String name;
private Address address;
}
public class Address {
private String homeAddress;
private String schoolAddress;
}
6.四种页面跳转传递参数方法:
①用ModelAndView方式:
@RequestMapping(value = "testModelAndView")
public ModelAndView testModelAndView(Student student) {//既有数据又有视图
ModelAndView modelAndView = new ModelAndView("success");
modelAndView.addObject("student", student);//相当于request.setAttribute()
return modelAndView;
}
②用ModelMap方式:
@RequestMapping(value = "testModelMap")
public String testModelMap(ModelMap mm) {
Student student = new Student();
student.setId(123);
student.setName("gg");
mm.addAttribute("student", student);
return "success";
}
③用Model方式
@RequestMapping(value = "testModel")
public String testModel(Model m) {
Student student = new Student();
student.setId(123);
student.setName("gg");
m.addAttribute("student", student);
return "success";
}
④用Map方式
@RequestMapping(value = "testMap")
public String testMap(Map<String,Object> m) {
Student student = new Student();
student.setId(123);
student.setName("gg");
m.put("Student", student);
return "success";
}
7.如果要在request中存放指定bean,在类头加@SessionAttributes注解。如:
@SessionAttributes("student")
public class SpringMVCHandler {}
8.如果要在request中按照类型存放bean,在类头加@SessionAttributes注解。如:
@SessionAttributes(types = {Student.class,Address.class})
public class SpringMVCHandler {}
9.@ModelAttribute注解修饰的方法会在任何一次请求前被调用,慎重使用。它里面的bean名称可以进行重定义,在其他方法调用到该bean的时候需要用(@ModelAttribute(“stu)Student student)指向。
二、视图解析器
1.简单介绍
视图的顶级接口:View
视图解析器:ViewResolver
2.常见的视图和解析器:InternalResourceViewResolver(在spring.xml文件中,参数有prefix、suffix。
作用是将字符串转换成以字符串名字命名的jsp页面)
public class JstlView extends InternalResourceView {}(源码)
springMVC解析jsp时,默认会使用InternalResourceView ,如果发现jsp中包含了jstl语言,会自动转换
为JstlView子类。
JstlView可以解析jstl、实现国际化操作。
3.国际化:针对不同地区、国家,进行不同的显示。
具体实现国际化的步骤:
①创建资源文件:基名_语言_地区.properties、基名_语言.properties(如果properties中不自动转换成ascii码,可以到jdk安装目录bin中用cmd执行native2ascii.exe文件,可转换ascii,再粘贴到资源文件中)
②配置springmvc.xml,加载资源文件。
<!-- 加载国际化资源文件 i18n是对应国际化资源文件名,以i18n开头的被加载进来-->
<!-- 1.将ResourceBundleMessageSource在程序加载时,加入springmvc:springmvc会自动查找
id="MessageSource"bean,如果有自动加载(就是id)
2.如果配置了ResourceBundleMessageSource,则该类会在程序响应人介入-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
③通过jstl使用国际化,需要jar包jstl.jar、standar.jar。需要在jsp上引用
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
4.<mvc:view-controller …>注解
通过springmvc.xml中配置如下标签,可越过controller直接调用其他页面,如:
(注:这个配置会让所有请求转入mvc:中匹配地址,忽略掉@RequestMapping())
<!-- view-name依然可以加上前缀和后缀-->
<mvc:view-controller path="handler/testMvcViewController" view-name="success"/>
如果需要配置和controller共存,需要加入如下注解:(建议配置文件提前加入,很多功能会用到)
<!-- 此配置是springmvc的基础配置,很多功能都需要该配置协调 -->
<mvc:annotation-driven></mvc:annotation-driven>
5.指定请求方式
地址栏输入controller地址跳到对应映射页面但地址栏不变的模式叫“请求转发模式”,地址栏改变“重定向模式”,如果想改变跳转方式可在return添加关键字如:
(注:此方式springmvc.xml中的前缀和后缀设置会失效)
//forward:请求转发
return "forward:/view/success.jsp";
//redirect:重定向
return "redirect:/view/success.jsp";
6.处理静态资源:html、css、js、图片、视频
在springmvc中,如果直接访问静态资源:404。原因:将所有的请求通过通配符“/”拦截,交给springMVC的入口DispatcherServlet去处理:找该请求对应的@RequestMapping,直接在地址栏访问的话就等同于@RequestMapping(“img.jpg”)。
解决静态方案:如果有springMVC对应的@RequestMapping则讲给spring处理,如果没有对应的@RequestMapping,则交给服务器tomcat默认的servlet处理。实现方法只需要增加一个配置(springmvc.xml : <mvc:default-servlet-handler />)
注:这个注解也必须加上:<mvc:annotation-driven ></mvc:annotation-driven>
7.类型转换
①springmvc内置一些常用的类型转换器。
②也可以自定义类型转换:
编写自定义类型转换器的类(实现一个Converter接口)
public class MyConverter implements Converter<String, Student>{
@Override
public Student convert(String source) {
//接收前端传来的字符串
String[] studentStrArr = source.split("-");
Student student = new Student();
student.setId(Integer.parseInt(studentStrArr[0]));
student.setName(studentStrArr[1]);
return null;
}
}
配置:将MyConverter加入到springmvc中:
<!-- 1.将自定义转换器纳入springmvcioc容器 -->
<bean id="myConverter" class="org.lanqiao.converter.MyConverter"></bean>
<!-- 2.将myConverter纳入springmvc提供的转化器bean中 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"/>
</set>
</property>
</bean>
<!-- 3.将conversionService注册到annotation-driven中 -->
<!-- 此配置是springmvc的基础配置,很多功能都需要该配置协调 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
测试方法:
前端text输入一个字符串:123-456转换后分别放入student
@RequestMapping(value = "testConverter")
public String testConverter(@RequestParam("studentInfo") Student stu) {
System.out.println(stu.getId()+","+stu.getName());
return "success";
}
三、数据格式化
1.实现步骤:
①配置:(该bean既可以实现格式化,又可以实现类型转换)
<!-- 配置数据格式化依赖的bean -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
②通过注解使用:
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;
@NumberFormat(pattern="###.#")//传入的值如:123.4
private int id;
四、错误处理、数据校验
1.错误消息:
需要验证的数据,springmvc要求,如果校验失败,将错误信息自动放入该对象后面挨着的BindingResult内,因此顺序不能变。如果要将控制台中的错误消息,可以将错误对象放入request域中,然后在jsp中从requestScope中取。
@RequestMapping(value = "testDateTimeFormat")//如果Student格式化出错,会将错误信息传入result中
public String testDateTimeFormat(Student stu,BindingResult result,Map<String,Object> map) {
System.out.println(stu.getId()+","+stu.getName()+","+stu.getBirthday());
if(result.getErrorCount()>0){
for(FieldError error :result.getFieldErrors()){
System.out.println(error.getDefaultMessage());
map.put("errors", result.getFieldErrors());
}
}
return "success";
}
jsp获取代码如下:
<c:forEach items="${requestScope.errors}" var="error">
${error.getDefaultMessage()}、</br>
</c:forEach>
2.数据校验:
JSR303格式校验,如下:
Constraint | 详细信息 |
---|---|
@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(value) | 被注释的元素必须符合指定的正则表达式 |
Hibernate Validator是JSR303的扩展,如下:
Constraint | 详细信息 |
---|---|
被注释的元素必须是电子邮箱地址 | |
@Length | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空 |
@Range | 被注释的元素必须在合适的范围内 |
①依赖的jar:
hibernate-validator.jar
classmate.jar
jboss-logging.jar
validatetion-api.jar
hibernate-validator-annotation-processor.jar
②配置:
此时:要实现Hibernate Validator/JSR303校验,必须实现springmvc提供的接口:ValidatorFactory
LocalValidatorFactoryBean是ValidatorFactory的一个实现类。
<mvc:annotation-driven ></mvc:annotation-driven>在springmvc容器中自动加载一个LocalValidatorFactoryBean类,可以直接实现数据校验。
<mvc:annotation-driven></mvc:annotation-driven>
③直接使用注解
五、Ajax请求SpringMVC,返回JSON格式数据
1.需要jar包:
添加包时,版本号尽量保持一致或相近。
jackson-annotation.jar
jackson-core.jar
jacksion-databin.jar
2.@ResponseBody
@ResponseBody:告诉springmvc,此时返回不是一个view页面,而是一个ajax调用的返回值。
客户端:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#testJson").click(function(){
//通过ajax请求springmvc
$.psot("handler/testJson",//服务器地址
/* {"name":"zs"}, */
function(result){//服务端处理完毕后的回调函数
for(var i = 0;i<result.length;i++){
alert(result[i].id);
alert(result[i].name);
alert(result[i].age);
}
}
);
});
});
</script>
服务端:
@ResponseBody//告诉springmvc,此时返回不是一个view页面,而是一个ajax调用的返回值
@RequestMapping(value = "testJson")
public List<Student> testJson() {
Student stu1 = new Student(1, "zs", 21);
Student stu2 = new Student(2, "ls", 22);
Student stu3 = new Student(3, "ws", 23);
List<Student> students = new ArrayList<>();
students.add(stu1);
students.add(stu2);
students.add(stu3);
return students;
}
六、SpirngMVC实现文件上传
1.springmvc和Servlet方式的本质一样,都是通过两个组件来实现。
Springmvc可以简化文件上传的代码,必须满足条件:实现MultipartResolver接口,该接口的实现类SpringMVC也已经提供CommonsMultipartResolver。
具体步骤:(直接使用CommonsMultipartResolver实现上传)
①jar包:commons-fileupload.jar、commons-io.jar
②配置:CommonsMultipartResolver
将其加入SpringIOC.xml容器
<!-- 配置:CommonsMultipartResolver,将其加入SpringIOC.xml容器
实现文件上传 id值是固定的 “multipartResolver” springioc初始化时,会自动寻找改名的bean,并加入ioc容器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 上传单位文件最大值 单位是B-->
<property name="maxInMemorySize" value="10240000"></property>
</bean>
③处理的方法:
客户端:
<form action="handler/testUpload" method="post" enctype="multipart/form-data">
<input type="file" name ="file">
描述:<input name="desc" type="text">
<input type="submit" value="上传">
</form>
服务端:
@RequestMapping(value = "testUpload")
public String testUpload(@RequestParam("desc") String desc,@RequestParam("file")MultipartFile file) throws IOException {
System.out.println(desc);
//输入流
InputStream inputStream = file.getInputStream();
//输出流
OutputStream fileOutputStream = new FileOutputStream("d:\\"+file.getOriginalFilename());
//字节循环写入
byte[] bs = new byte[1024];
int len = -1;
while((len = inputStream.read(bs)) != -1){
fileOutputStream.write(bs,0,len);
}
inputStream.close();
fileOutputStream.close();
return "success";
}
2.拦截器:
Springmvc:要想实现拦截器,必须实现一个接口HandlerInterceptor,接口中有三个方法:
preHandle:拦截请求
postHandle:拦截相应
afterCompletion:当页面被渲染完毕后出发
①编写拦截器:拦截器类实现HandlerInterceptor接口。
②配置:将写好的拦截器配置到springmvc中。
七、异常处理
**1.Springmvc:**HandlerExceptionResolver接口
这个接口的每一个实现类,都是异常的一种处理方式。
ExceptionHandlerExecptionResolver:主要提供了@ExceptionHandler注解, 通过注解处理异常。
注:@ExceptionHandler标识的方法参数,必须是异常类型的Throwable或子类,不能包含其他参数。
// 该方法可以捕获本类中,抛出的ArithmeticException异常ArrayIndexOutOfBoundsException
@ExceptionHandler({ ArithmeticException.class,ArrayIndexOutOfBoundsException.class })
public ModelAndView handlerArithmeticException(Exception e) {
System.out.println(e+"===============");
ModelAndView mv = new ModelAndView("error");
mv.addObject("e",e);
return mv;
}
@RequestMapping("testExceptionHandler2")
public String testExceptionHandler2() {
int[] nums = new int[2];
System.out.println(nums[2]);
return "success";
}
异常处理的优先级,路径最短优先
如果一个方法抛出一个ArithmeticException异常,该类中有两个异常处理方法:
会优先选择handlerArithmeticException1方法来处理。
@ExceptionHandler({ ArithmeticException.class})
public ModelAndView handlerArithmeticException1(Exception e) {
@ExceptionHandler({ ArithmeticException.class })
public ModelAndView handlerArithmeticException2(ArithmeticException) {
总结:如果一个方法用于处理异常,并且只处理当前类的异常:方法前加@ExceptionHandler
如果一个方法用于处理异常,并且处理所有类的异常:类前加@ControllerAdvice、方法前加@ExceptionHandler。
2.ResponseStatusExceptionResolver,自定义异常显示页面
//调用端
@RequestMapping("testMyException")
public String testMyException(@RequestParam("i") Integer i) throws MyArrayIndexOutofBoundsException {
if(i == 3){
throw new MyArrayIndexOutofBoundsException();
}
int[] nums = new int[2];
System.out.println(nums[2]);
return "success";
}
@ResponseStatus(value = HttpStatus.FORBIDDEN,reason="数组越界!")
public class MyArrayIndexOutofBoundsException extends Exception{//自定义异常
}
八、SSM整合
Spring—SpringMVC—Mybatis
Spring-----Mybatis:需要整合:将Mybatis的SqlSessionFactory交给Spring。
Spring-----SpringMVC:就是将两个框架各自配置一遍。
1.SM整合步骤:
①引入jar:
mybatis-spring.jar spring-tx.jar spring-jdbc.jar spring-expression.jar spring-context-supoprt.jar
spring-core.jar spring-context.jar spring-beans.jar spring-aop.jar spring-web.jar
commons-logging.jar commons-dbcp.jar ojdbc.jar mybatis.jar log4j.jar commons-pool.jar
2.类—表
Student-----student
3.spring配置文件applicationContext.xml
(与spring整合时,Mybati配置文件conf.xml可以省略)
九、表单标签
1.表单标签:
自定义标签:el/jstl
Spring EL:支持各种类型的请求方式(查询doGet、增加doPost、删除doDelet、修改doPut)
可以将对象和表单绑定 对象的属性----表单里的path值一一对应。
使用Idea配置SpringMVC项目:
新建项目选择Spring>SpringMVC创建自动下载相关的jar
处理jar:Project Structure>Arifacts>fix:miss all…
开发代码:
①页面引入标签库:<%@taglib prefix=“form” uri=“http://www.springframework.org/tags/form” %>
使用form时,springmvc标签默认自动从“command”的对象中获取值,如果后端用的事map.put()名字不是command,需要手工指定:command=“cd” 和 modelAttribute=“cd” 二选一定义即可。
public String testForm(Map<String,Person> map){
Person person = new Person();
person.setName("zs");
map.put("cd",person);
return "index";
}
2.支持各种表单提交方式:
①编写method=“put|delete”
②过滤器:为了让浏览器支持put|delete等请求,需要web.xml配置过滤器HiddenHttpMethodFilter。
<!-- 用于支持delete put等请求-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
HiddenHttpMethodFilter会将全部请求中name=“_method”的隐藏域 进行put|delete处理。
十、checkbox:自动绑定request域中的值
前端有复选框可初始化勾选数量,动态获取复选框数量。
后端:
@RequestMapping("/testForm")
public String testForm(Map<String,Object> map){
Person person = new Person();
person.setSix(true);
List<String> hobbies = new ArrayList<>();
hobbies.add("football");
hobbies.add("basketball");
person.setHobbies(hobbies);
Map<String,String> allHobbies = new HashMap<>();
allHobbies.put("football","足球");
allHobbies.put("basketball","篮球");
allHobbies.put("pingpang","乒乓球");
allHobbies.put("yumao","羽毛球");
map.put("command",person);
map.put("allHobbies",allHobbies);
return "index";
}
前端:
<form:form action="testForm">
<%--复选框--%>
<form:checkboxes path="hobbies" items="${allHobbies}"/>
<%--单选框--%>
<form:radiobuttons path="favirateBall" items="${allHobbies}"/>
<%--下拉框1--%>
<form:select path="favirateBall" items="${allHobbies}"/>
<%--下拉框2--%>
<form:select path="favirateBall" ">
<form:option value="football">足球</form:option>
<form:option value="basketball">篮球</form:option>
<form:option value="pingpang">乒乓</form:option>
</form:select>
<%--下拉框3--%>
<form:select path="favirateBall" >
<form:options items="${allHobbies}"/>
</form:select>
注:下拉框优先级:方式2、3同时存在,优先使用方式2
方式1、2同时存在,优先使用方式1