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.