SpringMVC_3.x_入门指南_3
SpringMVC 3.x
博文目录:
使用springmvc如何接收页面的传值
我们仍然使用前两篇博文中搭建好的框架!再新添一些东西,用来完成这篇新博文,木有高深的东西,仅仅为了记录一个入门程序员的实战历程!不喜勿喷,欢迎交流!
目前的进度仍然是没有连接数据库的!
新建一个Student类
package com.cn.pojo; public class Student { private Integer id; private String name; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
新建StudentController
@Controller @RequestMapping("/student") public class StudentController { @RequestMapping(value="/add",method=RequestMethod.GET) public String addForm(){ System.out.println("addForm..."); return "student/add"; } @RequestMapping(value="/add",method=RequestMethod.POST) public String add(Integer id,String name,String address,String country){ System.out.println("id="+id+",name="+name+",address="+address+",country"+country); return "student/add"; } }
新建student文件夹,在此文件夹中新建add.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>添加学生</title> </head> <body> <h1>添加学生</h1> <form action="/student/add" method="post"> 学号:<input type="text" name="id"/> <br/> 姓名:<input type="text" name="name"/> <br/> 地址:<input type="text" name="address"/> <br/> 国籍:<input type="text" name="country"/> <br/> <input type="submit" value="添加"/> <br/> </form> </body> </html>
启动服务器,访问:localhost/student/add
到达add.jsp,填写完整的表单,提交!!!
在控制台会显示接收到的信息!!!!
id=1,name=tom,address=hangzhou,country=USA
问题:
如果我的表单列表非常多,那样的话,我的方法中岂不是要写非常多的参数用来接收!这是我不想要的,有些参数是在一个对象中的(id,name,address),能否使用对象来接收呢?试试呗!!
@RequestMapping(value="/add",method=RequestMethod.POST) public String add(Student student,String country){ System.out.println("id="+student.getId()+",name="+student.getName()+",address="+student.getAddress()+",country="+country); return "student/add"; }
经验证,完美实现接收,真是太棒了!
问题:
如果我的Student类中也有一个属性叫country,那么传的参数是给student,还是参数列表中的country呢?
package com.cn.pojo; public class Student { private Integer id; private String name; private String address; private String country; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
@RequestMapping(value="/add",method=RequestMethod.POST) public String add(Student student,String country){ System.out.println("student.country: "+student.getCountry()+",country: "+country); return "student/add"; }
你猜出结果了吗?结果是让人惊叹的!竟然同时给两项都赋值了。
student.country=country=**
问题:
如果Student中有一个属性是Country对象,Country类中有一个属性是country,那么我们的传值又是怎样的呢?
结论:
值只会直接传值,也就是说,不会给Student对象中的Country对象赋值!
那么如何给我们的student对象中的Country对象赋值呢?
使用下面的表单样式可以实现:
<form action="/student/add" method="post"> 学号:<input type="text" name="id"/> <br/> 姓名:<input type="text" name="name"/> <br/> 地址:<input type="text" name="address"/> <br/> 国籍:<input type="text" name="coun.country"/> <br/> <input type="submit" value="添加"/> <br/> </form>
coun是Student类中的Country类型的变量;
既然说过了基本的表单,我们把特殊的文件上传一块说了吧!!!
其实文件上传也是表单提交,只是有那么一点点的区别。
我们新建一个用于文件上传的JSP,放到views下面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>文件上传</title> </head> <body> <h1>文件上传</h1> <form action="/upload" method="post" enctype="multipart/form-data"> Name:<input type="text" name="desc"/> <br/> <input type="file" name="file"/> <br/> <input type="submit" value="上传" /> </form> </body> </html>
文件上传的表单有几点需要注意:
一定要设置enctype="multipart/form-data"
上传表单的组件是:input type="file"
使用method="post"进行提交
我们新建一个UploadController
@Controller public class UploadController { @RequestMapping(value="/upload",method=RequestMethod.GET) public String uploadForm(){ return "upload"; } @RequestMapping(value="/upload",method=RequestMethod.POST) public String upload(String desc,MultipartFile file){ System.out.println("desc= "+desc); System.out.println("name: "+file.getName()); System.out.println("ContentType: "+file.getContentType()); System.out.println("OriginalFilename: "+file.getOriginalFilename()); System.out.println("Size: "+file.getSize()); return "upload"; } }
启动容器,访问:localhost/upload
选择一个文件上传,哈哈,报错了吧!!!
意思是:你配置文件上传解析器了吗?呵呵,我们确实啥都没有配置呢!!
在springmvc-servlet.xml中添加一项文件上传解析器:
<!-- 文件上传解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="100000"/> </bean>
SpringMVC提供的文件上传解析器,CommonsMultipartResolver,下面配置的一个属性:
maxUploadSize,你懂的!当然是最大上传体积呀,单位是字节(Byte)!!
文件上传要用到:commons-fileupload,所以我们要在我们的pom.xml中加入我们的commons-fileupload
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</version> </dependency>
启动服务器,选择一个英文名的图片:1.jpg
获得的输出结果为:
desc: hello
name: file
ContentType: image/jpeg
OriginalFilename: 1.jpg
Size: 28119
getName方法获取的是表单的name值,而getOriginalFilename获取的是图片的名称;
怎么存呢?
使用到IO部分内容,这里不多说,只说一种最简单的!
@RequestMapping(value="/upload",method=RequestMethod.POST) public String upload(String desc,MultipartFile doc){ System.out.println("desc= "+desc); System.out.println("name: "+doc.getName()); System.out.println("ContentType: "+doc.getContentType()); System.out.println("OriginalFilename: "+doc.getOriginalFilename()); System.out.println("Size: "+doc.getSize()); try { doc.transferTo(new File("c:/upload",doc.getOriginalFilename())); } catch (Exception e) { e.printStackTrace(); } return "upload"; }
以OriginalFilename为文件名,存到c盘的upload目录中。
如果我们上床一个带中文的图片:2013课表.png
OriginalFilename: 2013è??è?¨.png
产生了乱码!!!怎么解决呢?转码呗!
@RequestMapping(value="/upload",method=RequestMethod.POST) public String upload(String desc,MultipartFile doc){ try { //将原来的编码转为UTF-8格式,然后存储 String fileName=new String(doc.getOriginalFilename().getBytes("ISO8859-1"), "UTF-8"); doc.transferTo(new File("c:/upload",fileName)); } catch (Exception e) { e.printStackTrace(); } return "upload"; }
文件上传暂时告一段落!下面干点啥呢?
一个网站如果只有文字是不是太单调了,我们是不是可以添点图片(非网上的图片)进去呢?
于是我们在webapp文件夹下建立了一个img文件夹,里面放了一张美女的图片1.jpg!
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>home.jsp</title> </head> <body> This is my JSP page. <br> <img alt="" src="/img/1.jpg"> </body> </html>
启动服务器,输入:localhost/home
前面我们也提到过,所有的请求都要经过 *控制器 SpringMVC认为图片也是要请求的,所以我们还需要配置对静态资源的访问;
最好的方式是让所有的静态文件夹放到一个文件夹中:static,注意:在struts中不能使用这个文件夹名称!!我暂时还不清楚为啥?知道的可以跟我说一下!
在springmvc-servlet.xml中配置对静态资源的访问:
<!-- 静态资源 --> <mvc:resources location="/static/" mapping="/static/**"/>
这样的话,所有的static中的静态资源都可以被我们访问到了!!!
问题:
我申请的域名是:www.t.com,但是我的主页在服务器上是/home请求的,我如何通过只访问www.t.com就相当于访问www.t.com/home呢?
我们可以在springmvc-servlet.xml中配置视图控制器:viewController
<!-- 视图控制器 --> <mvc:view-controller path="/" view-name="/home"/>
最后我们再来看一下SpringMVC中的拦截器
拦截器相当于Servlet中的过滤器和Struts中的拦截器。
怎么使用呢?
1,写我们自己的拦截器,继承SpringMVC提供的拦截器适配器类:HandlerInterceptorAdaptor
2,重写父类的preHandler方法,返回值为true则放行,返回值false则不放行;
3,在springmvc-servlet.xml中配置拦截器
对应的代码如下:
public class MyInterceptor extends HandlerInterceptorAdapter{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor..."); //返回值为true则通过,false则不通过 return false; } }
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.cn.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
path="/**" : 表示所有的请求都要经过此拦截器!
你要问了,我不想拦截掉所有的页面,至少你得让我看到/home页面吧!
我们可以排除掉一些页面,配置如下:
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.cn.interceptor.MyInterceptor"> <property name="excludeUrls"> <list> <value>/home</value> <value>/</value> </list> </property> </bean> </mvc:interceptor> </mvc:interceptors>
在bean中添加property,里面装了若干个url,表示我们排除掉的url;
除了配置此list外,你需要在咱们的拦截器里接收配置的urls;
源码如下:
public class MyInterceptor extends HandlerInterceptorAdapter{ private List<String> excludeUrls;//用来存放配置的urls @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(request.getRequestURI()); for (String url : excludeUrls) { if(request.getRequestURI().equalsIgnoreCase(url)){ return true; } } if(request.getSession().getAttribute("curr_user")!=null){ return true; }else{ return false; } } //配置文件中的list,通过set方法向excludeUrls中添加配置的urls public void setExcludeUrls(List<String> excludeUrls) { this.excludeUrls = excludeUrls; } }
这样的话,我们就可以访问我们的/home和/了,但是我们的美女却找不到了!!!原因是我们无法访问到/static/里的内容,现修改如下:
public class MyInterceptor extends HandlerInterceptorAdapter{ private List<String> excludeUrls; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(request.getRequestURI()); for (String url : excludeUrls) { //如果url请求是以/static/开头的,直接通过... if(request.getRequestURI().equalsIgnoreCase(url)||request.getRequestURI().startsWith("/static/")){ return true; } } if(request.getSession().getAttribute("curr_user")!=null){ return true; }else{ return false; } } public void setExcludeUrls(List<String> excludeUrls) { this.excludeUrls = excludeUrls; } }
对于拦截器拦截掉的请求,也就是return false;的情况,我们一般情况下是让其跳转到某一个页面(比如:登录页,/home等等),如何实现?
第一种方式:
直接使用preHandler中提供的response对象:
public class MyInterceptor extends HandlerInterceptorAdapter{ private List<String> excludeUrls; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(request.getRequestURI()); for (String url : excludeUrls) { if(request.getRequestURI().equalsIgnoreCase(url)||request.getRequestURI().startsWith("/static/")){ return true; } } if(request.getSession().getAttribute("curr_user")==null){ response.sendRedirect("/home"); } return true; } public void setExcludeUrls(List<String> excludeUrls) { this.excludeUrls = excludeUrls; } }
第二种方式:
通过抛出异常,并配置异常处理来完成跳转:
//自定义异常 public class MyValidateException extends RuntimeException { private static final long serialVersionUID = 1L; }
public class MyInterceptor extends HandlerInterceptorAdapter{ private List<String> excludeUrls; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(request.getRequestURI()); for (String url : excludeUrls) { if(request.getRequestURI().equalsIgnoreCase(url)||request.getRequestURI().startsWith("/static/")){ return true; } } if(request.getSession().getAttribute("curr_user")!=null){ return true; }else{ //如果没有登录,抛出异常,调用异常解析器,决定跳转 throw new MyValidateException(); } } public void setExcludeUrls(List<String> excludeUrls) { this.excludeUrls = excludeUrls; } }
在springmvc-servlet.xml中配置异常解析器:
<!-- 异常解析器 --> <bean id="handlerExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="com.cn.exception.MyValidateException">redirect:/home</prop> </props> </property> </bean>
当出现:MyValidateException时,执行redirect到/home.