Spring-MVC
零、目录
- Spring-MVC介绍
- Spring-MVC入门案例
- 使用注解形式简化Cotroller
- 配置资源解析器
- 三种方式获取页面传递过来得参数
- 获取参数时的乱码问题
- 日期获取问题
- 同名参数提交问题
- 提交参数名称与接收时的变量名称不一致的问题
- 文件上传
- 重定向和转发
一、Spring-MVC介绍
- 主要负责前端 控制的框架 , 主要负责页面和servlet之间的交互
- 可以与Spring无缝衔接
- 回顾Servlet的缺点:
- 一个Servlet需要在web.xml中配置8行配置
- 一个servlet只能处理一个逻辑 , 一张表最少需要增、 删、 改、 查 四个servlet , 在web.xml文件中至少会有32+n行配置
- 获取的属性只能获取到字符串类型 , 需要自己手动转换成需要的类型。
- 获取参数比较繁琐 , 需要手动封装到bean中。
- Spring-mvc优点:
- 不管工程中有多少个控制器(servlet) , 只需要在web.xml中配置一个Spring自带的Servlet分发器即可
- 在Spring-mvc中cotroller代替了servlet , 一个cotroller可以有多个业务处理
- 获取的参数支持自动转换 , 而且支持对象的自动封装
二、Spring-mvc入门案例
- 导入jar包:
在web.xml文件中配置Spring-mvc请求分发器
<!-- 配置servlet分发器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/applicationContext-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.action</url-pattern><!-- / --> </servlet-mapping>
添加Spring配置文件 applicationContext-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd "> <!-- 配置控制層 --> <bean name="/hello.action" class="com.tj.controller.HelloController2"></bean> <!-- 有springmvc注解之後就不用手動配置了 --> </beans>
创建HelloCotroller.java实现Cotroller接口
public class HelloController2 implements Controller{ public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView(); //返回信息 mav.addObject("msg", "需要返回的信息"); //指定返回的视图 mav.setViewName("index.jsp"); return mav; } }
- 测试: 访问本机ip地址:端口号/工程名/hello.action时, 跳转回主页面
- SpringMVC工作过程 , 在浏览器中输入地址访问时会由Spring分发器拦截 , 通过Spring容器找到相应的controller后执行对应的方法 。
三、通过注解形式简化Controller
在Spring配置文件中开启包扫描 ,开启注解模式, 开启SpringMVC注解开关 , 并引入mvc的约束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd "> <!-- 开启注解模式 --> <context:annotation-config /> <!-- 开启包扫描 --> <context:component-scan base-package="com.tj"></context:component-scan><!-- 扫描com.tj子包下的所有类 --> <!-- 配置控制層 --> <!-- <bean name="/hello.action" class="comtj.controller.HelloController"></bean> --><!-- 有springmvc注解之後就不用手動配置了 --> <!-- 開啓mvc注解 --> <mvc:annotation-driven/> </beans>
创建controller
@Controller public class HelloController { @RequestMapping("/hello.action") public String helloaction(Model m){ m.addAttribute("msg" , "哈哈哈哈哈"); return "index.jsp"; } }
- SpringMVC的执行流程:
- 补充说明:
- 当web工程修改名字的时候 , 还需要修改myeclipse向tomcat配置项目的名称
四、配置资源解析器
在spring配置文件applicationContext-mvc.xml中配置资源解析器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd "> <!-- 开启注解模式 --> <context:annotation-config /> <!-- 开启包扫描 --> <context:component-scan base-package="com.tj"></context:component-scan><!-- 扫描com.tj子包下的所有类 --> <!-- 配置控制層 --> <!-- <bean name="/hello.action" class="comtj.controller.HelloController"></bean> --><!-- 有springmvc注解之後就不用手動配置了 --> <!-- 開啓mvc注解 --> <mvc:annotation-driven/> <!-- 配置資源解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
修改controller层方法中的return语句 , 只需要返回页面的名称即可 , 资源解析器会自动拼接前缀和后缀
@RequestMapping("/hello.action") public String helloaction(Model m){ m.addAttribute("msg" , "哈哈哈哈哈"); //请求转发到WEB-INF下的Hello.jsp页面 return "Hello"; }
五、获取页面提交参数的三种方式
- 假设需要获取表单提交的name属性
通过HttpServletRequest方式获取页面提交的参数
public class HelloController2 implements Controller{ public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView(); String name = (String) request.getAttribute("name"); //返回信息 mav.addObject("msg", "需要返回的信息"); //指定返回的视图 mav.setViewName("index.jsp"); return mav; } }
快速获取参数的方式
@RequestMapping("/hello.action") public String helloaction(String name , Model m){ //需要参数名称 与表单中name属性一致才能获取到 //获取到之后会自动进行类型转换 //将参数带到页面显示 m.addAttribute("msg" , name); return "Hello"; }
使用对象把获取到的参数直接封装
- 这种方式需要bean中的属性名称与表单的name属性一致
- 获取到的参数会自动转换为bean中 的类型
- 要求bean中必须要有set方法和无参构造
- 参数判空 , 参数有效性的检验可以放在bean中的set方法中进行
当bean中有自定义类型时,需要指明层级关系 如: user类中有dog属性 , dog有自己的name , 这时表单中的name应该为name=“dog.name”
@RequestMapping("/hello.action") public String helloaction(User user, Model m){ m.addAttribute("msg" , "哈哈哈哈哈"); return "Hello"; }
六、 中文乱码问题
- 使用Spring-mvc代替servlet层之后 , 不在使用request , 和response 对象了, 但是乱码问题 依然存在
解决乱码问题:
- 在jsp页面中指定pageEncoding=“utf-8”
并且在web.xml配置文件中配置Spring-Mvc自带的过滤器
<!-- 配置Spring自帶的亂碼過濾器 --> <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>
但是Spring自带的过滤器中只提供题post方法对应的过滤 , 对get方法的请求没有做处理(mmp) , 所以尽量使用post吧 。
七、 日期问题
- 浏览器 提交日期格式的参数时 格式为yyyy/MM/dd
- 而Java中Date类默认的日期格式为yyyy-MM-dd
- 所以 如果不做处理浏览器会爆出400的错误
解决办法:在controller层添加日期格式转换的方法 , 如果多出需要添加可以写一个BaseController类 , 并且把一些常用的功能方法 放入其中 , 后续所有的Controller继承这个BaseController 。
//日期格式转化 , 使Spring日期格式与浏览器日期个数匹配 @InitBinder public void initBinder(ServletRequestDataBinder binder){ binder.registerCustomEditor(Date.class, new CustomDateEditor( new SimpleDateFormat("yyyy-MM-dd"), true)); }
八、 多个同名参数提交问题
- 如果提交像复选框一类 , 相同name多个值的参数时,若接收参数使用的是String类型 , 则spring会把 多个值用“,”拼接起来 , 合成一个String;若接收参数时使用String[] 接收 , 则会把多个同名 参数自动放入这个String[] 数组中 。
九、提交的参数名与接收时声明的变量名不一只问题
可以通过@RequestParam注解解决此问题
@RequestMapping("/hello.action") public String helloaction(Model m , @RequestParam("name")String 名字){ //使用“名字”这个变量接收了表单的name属性 m.addAttribute("msg" , "哈哈哈哈哈"); return "Hello"; }
- @RequestParam的使用
- 当只需要指定接收参数的name时 , 可以直接写@RequestParam(“xxxx”) , 但是 , 此时实际上是使用的@RequestParam的value属性 , 所以规范的写法应该是@RequestParam(value=”xxxx”)
- @RequestParam还可以指定参数的默认值 , 当表单提交的属性为空 , 或是获取不到该属性时 , 使用默认值:@RequestParam(value=”xxxx” , defaultValue=”好像没有值啊”)
- @RequestParam的required属性用于指定该参数是不是必须有值 , 如果required=“true” ,表单值为空或或者获取不到的情况下会报错
十、 文件上传
修改表单提交的类型enctype的值
<form action="register.action" method="post" enctype="multipart/form-data">
在Spring配置文件中配置文件上床解析器
<!-- 配置文件上传解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"></property> </bean>
在Controller层中对应对应的方法列表中添加MultipartFile参数
//文件上传 @RequestMapping("/register.action") public String register( Model m , MultipartFile photo){ String fillename = photo.getName(); String originalFilename = photo.getOriginalFilename(); long size = photo.getSize(); System.out.println("字段名:"+fillename); System.out.println("文件名:"+originalFilename); System.out.println("文件大小:"+size); m.addAttribute("msg", originalFilename+"上传成功!"); return "Hello"; }
十一、转发和重定向
- 重定向: 两次请求 , 两次响应, 不能传递参数 , 地址会发生改变
- 转发: 一次请求 , 一次响应 , 可以再请求链中传递参数 , 地址不会发生改变
SpringMVC中默认使用请求转发
@RequestMapping("/hello.action") public String helloaction(Model m , @RequestParam(value="name" )String 名字){ m.addAttribute("msg" , "哈哈哈哈哈"); return "Hello"; }
- 如果需要重定向 , 需要在返回的地址中添加redirect
@RequestMapping(“/rrr.action”)
public String helloaction(Model m , String name){
m.addAttribute(“msg” , “哈哈哈哈哈”);
return "redirect:hello.action";//重定向的是一个请求 , 而不是资源的地址
}
5. 注意:
1. 一般情况下除了主页面在webroot目录下 , 其他的页面文件都放在WEB-INF目录下, 不能直接访问, 需要访问时 , 先请求Controller层中对应的逻辑处理方法后转发到访问的资源 。
2. 请求重定向时也不能直接访问WEB-INF下的资源 , 所以重定向时redirect:后跟的是一个请求 , 而不是资源的地址