SpringMVC_3.x_入门指南_3

SpringMVC 3.x

博文目录:

  1. 接收表单值
  2. 文件的上传
  3. 静态资源访问
  4. 视图解析器
  5. 拦截器
  6. 异常处理

 

使用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
选择一个文件上传,哈哈,报错了吧!!!

写道
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?

意思是:你配置文件上传解析器了吗?呵呵,我们确实啥都没有配置呢!!


在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

写道
警告: No mapping found for HTTP request with URI [/img/1.jpg] in DispatcherServlet with name 'springmvc'

 前面我们也提到过,所有的请求都要经过 中央控制器 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.

 

 

 

 

 

 

猜你喜欢

转载自hunthon.iteye.com/blog/1962079