SpringMVC知识点小结

是基于Spring3.1的。从Spring3.0之后,SpringMVC开始广泛使用基于注解的控制器,而不是继承AbstractController 类或者实现Controller接口了。虽然Struts2现在很流行,但是,个人觉得SpringMVC十分优雅,不比Struts2差。至少我在公司中,从来没用用过SpringMVC,而且貌似在国内的公司用SpringMVC做WEB层的不多吧。不过对Spring感兴趣的话,可以自己有空研究一下。

这下的是自己的一点总结,是一些常用的SpringMVC知识点。

-------------------------------------------------启动SpringMVC-------------------------------------------------

1.要导入的JAR文件

必须的
org.springframework.aop-3.1.0.RELEASE.jar
org.springframework.asm-3.1.0.RELEASE.jar
org.springframework.beans-3.1.0.RELEASE.jar
org.springframework.context-3.1.0.RELEASE.jar
org.springframework.core-3.1.0.RELEASE.jar
org.springframework.expression-3.1.0.RELEASE.jar

数据访问
org.springframework.jdbc-3.1.0.RELEASE.jar
org.springframework.orm-3.1.0.RELEASE.jar
org.springframework.transaction-3.1.0.RELEASE.jar

测试
org.springframework.test-3.1.0.RELEASE.jar
com.springsource.org.junit-4.7.0.jar

WEB
org.springframework.web-3.1.0.RELEASE.jar
org.springframework.web.servlet-3.1.0.RELEASE.jar

JSTL标签
com.springsource.javax.servlet.jsp.jstl-1.1.2.jar
com.springsource.org.apache.taglibs.standard-1.1.2.jar

AOP
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

日志
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar

文件上传
com.springsource.org.apache.commons.fileupload-1.2.0.jar
com.springsource.org.apache.commons.io-1.4.0.jar

2.启动SpringMVC
web.xml

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:beans.xml</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
	<servlet-name>spring</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>spring</servlet-name>
	<url-pattern>*.html</url-pattern>
</servlet-mapping>

3.spring-servlet.xml

<!-- 配置要扫描的控制器 -->
<context:annotation-config/>
<context:component-scan base-package="org.springfuncs.web.controller"/>


<!-- 配置视图解析器 -->
<bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
	<property name="prefix" value="/WEB-INF/jsp/"/>
	<property name="suffix" value=".jsp"/>
</bean>

-------------------------------------------------@Controller详解-------------------------------------------------


在一个POJO的上面打上@Controller注解,就表示此类是一个MVC控制器
例如:
@Controller
public class UserController {

}

-------------------------------------------------@RequestMapping详解-------------------------------------------------

用于处理映射路径,一本可以用于类上面或方法上面

value  请求的URL
method 请求的方法 
params 请求参数  http://localhost:8080/spring1/registerUI.html?id=123&name=tom

headers 请求头信息
consumes
produces


例如:
@Controller
@RequestMapping("/")
public class UserController {

	@RequestMapping("/registerUI.html")
	public String registerUI() {
		return "registerUI";
	}

	或者

	@RequestMapping(value = "/registerUI.html", method = RequestMethod.GET, params = { "id", "name" })
	public String registerUI(Integer id, String name) {
		System.out.println("请求参数:" + id);
		System.out.println("请求参数:" + name);
		return "registerUI";
	}
	
	//要是有 params = { "id", "name" }则HTTP地址必须提供参数
	//若写成 http://localhost:8080/spring1/registerUI.html报错
}

-------------------------------------------------ModelAndView详解-------------------------------------------------

用于返回模型与视图

用法一:(推荐)

return new ModelAndView("registerSuccess", "user", user); 视图名、属性名、属性值

用法二:(推荐)

用Map构造 属性名、属性值
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("user", user);
modelMap.put("aaa", "one");
modelMap.put("bbb", "two");
return new ModelAndView("registerSuccess", modelMap); 视图名、Map对象

用法三:

ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user", user);
		
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("aaa", "one");
modelMap.put("bbb", "two");
modelAndView.addAllObjects(modelMap);
modelAndView.setViewName("registerSuccess");
return modelAndView;

-------------------------------------------------@RequestParam详解-------------------------------------------------
用于绑定请求参数

例如:

value 请求参数的名
required 是否必须 
defaultValue 默认值(支持不好,不推荐使用)

@RequestMapping(value = "/register.html", method = RequestMethod.POST)
public ModelAndView register(
		@RequestParam(value = "username", required = true) String username, 
		@RequestParam(value = "password", required = true) String password,
		@RequestParam(value = "email", required = false, defaultValue = "unknown") String email, 
		@RequestParam(value = "age", required = false) Integer age) {

	User user = new User();
	user.setUsername(username);
	user.setPassword(password);
	user.setEmail(email);
	user.setAge(age);
	userService.register(user);

	return new ModelAndView("registerSuccess", "user", user);
}

-------------------------------------------------使用命令表单绑定请求参数 详解-------------------------------------------------
@RequestMapping(value = "/register.html", method = RequestMethod.POST)
public ModelAndView register(User user) {  //这里的User对象绑定提交的表单
	userService.register(user);
	return new ModelAndView("registerSuccess", "user", user);
}

-------------------------------------------------使用 Servlet原生API 详解-------------------------------------------------

@RequestMapping(value = "/register.html", method = RequestMethod.POST)
public ModelAndView register(HttpServletRequest request,HttpServletResponse response,HttpSession session) {
	
	//session
	session.setAttribute("sessionId", "9876");
	String sessionid=(String) session.getAttribute("sessionId");
	
	//response和cookie
	response.addCookie(new Cookie("c_name", "c_value"));
	Cookie[]cookies=request.getCookies();
	for(Cookie c:cookies){
		if(c.getName().equals("c_name")){
			System.out.println(c.getValue());
		}
		//System.out.println(c.getName()+"-->"+c.getValue());
	}
	
	//request
	String username = WebUtils.findParameterValue(request, "username");
	
	或者
	
	String username = null;
	Integer age = null;
	try {
		username = ServletRequestUtils.getStringParameter(request, "username");
		age = ServletRequestUtils.getIntParameter(request, "age");
	} catch (ServletRequestBindingException e) {
		e.printStackTrace();
	}
	return null;
}

------------------------------------------------验证 详解-------------------------------------------------
package org.springfuncs.web.validator;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springfuncs.domain.User;

/**
 * 表单验证组件 实现Validator接口
 */
@Component
public class UserValidtor implements Validator {

	@Override
	public boolean supports(Class<?> clazz) {
		return User.class.isAssignableFrom(clazz);
	}

	@Override
	public void validate(Object target, Errors errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "required.username");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "required.password");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "required.email");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "birthday", "required.birthday");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age", "required.age");

		User user = (User) target;
		if (user.getEmail() != null && !"".equals(user.getEmail())) {
			// Email的正则表达式
			String regex = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$";
			if (!user.getEmail().matches(regex)) {
				errors.rejectValue("email", "invalid.email");
			}
		}
	}
}

messages_zh_CN.properties

required.username=username 是必须的
required.password=password 是必须的
required.email=email 是必须的
required.birthday=birthday 是必须的
required.age=age 是必须的

invalid.email=非法的Email地址

typeMismatch.birthday=非法的 birthday 格式
typeMismatch.age=非法的 age 格式

spring-servlet.xml 添加如下配置

<context:component-scan base-package="org.springfuncs.web.validator"/>

<!-- 配置资源文件 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basename" value="messages"/>
</bean>

UserController 编写如下:

@RequestMapping(value = "/register.html", method = RequestMethod.POST)
public String register(@ModelAttribute("user") User user, BindingResult result) {
	userValidtor.validate(user, result); // 验证
	if (result.hasErrors()) {
		return "registerUI";
	} else {
		userService.register(user);
		return "registerSuccess";
	}
}

------------------------------------------------Spring表单详解-------------------------------------------------

package org.springfuncs.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springfuncs.domain.Form;

@Controller
@RequestMapping("/")
public class FormController {

	@RequestMapping("/formUI.html")
	public String formUI(@ModelAttribute("form") Form form) {

		/** 设置默认值 */
		form.setId(9999);
		form.setName("your name");
		// form.setPassword("your password"); //TODO 密码框怎么设置默认值呢?
		form.setSex("1");
		form.setLove(new String[] { "1", "2", "3" });
		form.setCity("2");
		form.setInfo("write something...");
		return "formUI";
	}

	/** 这是一个很笨的方法,仅仅为了演示而已 */
	@RequestMapping("/doForm.html")
	public ModelAndView doForm(@ModelAttribute("form") Form form) {

		// 处理 sex
		if (form.getSex().equals("1")) {
			form.setSex("男");
		} else {
			form.setSex("女");
		}

		// 处理 city
		if (form.getCity().equals("1")) {
			form.setCity("北京");
		} else if (form.getCity().equals("2")) {
			form.setCity("上海");
		} else if (form.getCity().equals("3")) {
			form.setCity("广州");
		}

		// 处理 love
		String[] love = form.getLove();
		StringBuffer bufLove = new StringBuffer();
		for (int i = 0; love != null && i < love.length; i++) {
			if (love[i].equals("1")) {
				bufLove.append("struts").append(",");
			} else if (love[i].equals("2")) {
				bufLove.append("hibernate").append(",");
			} else if (love[i].equals("3")) {
				bufLove.append("spring").append(",");
			}
		}
		bufLove.deleteCharAt(bufLove.length() - 1);
		form.setLove(new String[] { bufLove.toString() });

		return new ModelAndView("formSuccess", "form", form);
	}
}


formUI.jsp

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

<form:form action="${pageContext.request.contextPath }/doForm.html" method="post" modelAttribute="form">
	<form:errors path="*" cssClass="error"/>
	<form:hidden path="id"/>
	<table>
		<tr>
			<td>姓名:</td>
			<td><form:input path="name"/></td>
		</tr>
		<tr>
			<td>密码:</td>
			<td><form:password path="password"/></td>
		</tr>
		<tr>
			<td>性别:</td>
			<td>
				<form:radiobutton path="sex" value="1"/>男
				<form:radiobutton path="sex" value="2"/>女
			</td>
		</tr>
		<tr>
			<td>爱好:</td>
			<td>
				<form:checkbox path="love" value="1"/>struts
				<form:checkbox path="love" value="2"/>hibernate
				<form:checkbox path="love" value="3"/>spring
			</td>
		</tr>
		<tr>
			<td>城市:</td>
			<td>
				<form:select path="city">
					<form:option value="">--请选择--</form:option>
					<form:option value="1">北京</form:option>
					<form:option value="2">上海</form:option>
					<form:option value="3">广州</form:option>
				</form:select>
			</td>
		</tr>
		<tr>
			<td>简介:</td>
			<td><form:textarea path="info" rows="3" cols="20"/></td>
		</tr>
		<tr>
			<td colspan="2"><input type="submit" value="注册"/></td>
		</tr>
	</table>
</form:form>

formSuccess.jsp

姓名:${form.name }<br />
密码:${form.password }<br />
性别:${form.sex }<br />
爱好:<c:forEach items="${form.love }" var="love">${love }</c:forEach><br />
城市:${form.city }<br />
简介:${form.info }<br />

------------------------------------------------Spring表单详解 2(推荐)-------------------------------------------------

***************************************
通常select的值都是从数据库中读取出后,        
封装成一个对象,						   
然后存入集合中,比如List
***************************************

package org.springfuncs.web.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springfuncs.domain.City;
import org.springfuncs.domain.Form;

@Controller
@RequestMapping("/")
public class FormController {

	// 重点
	@ModelAttribute("cityList")
	public List<City> populateCity() {
		List<City> cityList = new ArrayList<City>();
		cityList.add(new City(1, "北京"));
		cityList.add(new City(2, "上海"));
		cityList.add(new City(3, "广州"));
		return cityList;
	}

	@RequestMapping("/formUI.html")
	public String formUI(@ModelAttribute("form") Form form) {

		/** 设置默认值 */
		form.setId(9999);
		form.setName("your name");
		// form.setPassword("your password"); //TODO 密码框怎么设置默认值呢?
		form.setSex("1");
		form.setLove(new String[] { "1", "2", "3" });
		// form.setCity(new City(2, "上海")); //不好用啊
		form.setInfo("write something...");
		return "formUI";
	}

	/** 这是一个很笨的方法,仅仅为了演示而已 */
	@RequestMapping("/doForm.html")
	public ModelAndView doForm(@ModelAttribute("form") Form form) {

		// 处理 sex
		if (form.getSex().equals("1")) {
			form.setSex("男");
		} else {
			form.setSex("女");
		}

		// 处理 love
		String[] love = form.getLove();
		StringBuffer bufLove = new StringBuffer();
		for (int i = 0; love != null && i < love.length; i++) {
			if (love[i].equals("1")) {
				bufLove.append("struts").append(",");
			} else if (love[i].equals("2")) {
				bufLove.append("hibernate").append(",");
			} else if (love[i].equals("3")) {
				bufLove.append("spring").append(",");
			}
		}
		bufLove.deleteCharAt(bufLove.length() - 1);
		form.setLove(new String[] { bufLove.toString() });

		return new ModelAndView("formSuccess", "form", form);
	}
}


创建自定义类型
package org.springfuncs.web.propertyeditor;

import java.beans.PropertyEditorSupport;

import org.springfuncs.domain.City;
import org.springfuncs.service.CityService;

/**
 * 实现自定义属性类型 继承PropertyEditorSupport类
 */
public class CityEditor extends PropertyEditorSupport {

	private CityService cityService;

	public CityEditor(CityService cityService) {
		this.cityService = cityService;
	}

	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		if (text != null && !"".equals(text)) {
			Integer id = Integer.parseInt(text);
			City city = cityService.findById(id);
			setValue(city);
		}
	}
}

装配自定义类型
package org.springfuncs.web.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;
import org.springfuncs.domain.City;
import org.springfuncs.service.CityService;
import org.springfuncs.web.propertyeditor.CityEditor;

/**
 * 绑定自定义类型 实现WebBindingInitializer接口
 */
public class FormBindingInitializer implements WebBindingInitializer {

	@Autowired
	private CityService cityService;

	@Override
	public void initBinder(WebDataBinder binder, WebRequest request) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		dateFormat.setLenient(false);
		binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
		binder.registerCustomEditor(City.class, new CityEditor(cityService));

	}
}

在spring-servlet.xml 中配置
<!-- 自定义属性类型 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
	<property name="webBindingInitializer">
		<bean class="org.springfuncs.web.util.FormBindingInitializer"/>
	</property>
</bean>


package org.springfuncs.service.impl;

import org.springframework.stereotype.Service;
import org.springfuncs.domain.City;
import org.springfuncs.service.CityService;

@Service
public class CityServiceImpl implements CityService {

	public static final City BEIJING = new City(1, "北京");
	public static final City SHANGHAI = new City(2, "上海");
	public static final City GUANGZHOU = new City(3, "广州");

	@Override
	public City findById(Integer id) {
		switch (id) {
		case 1:
			return BEIJING;
		case 2:
			return SHANGHAI;
		case 3:
			return GUANGZHOU;
		default:
			return null;
		}
	}
}

<form:select path="city">
	<form:option value="">--请选择--</form:option>
	<form:options items="${cityList }" itemLabel="name" itemValue="id"/>
</form:select>

另一种
<form:select path="city">
	<form:option value="">--请选择--</form:option>
	<form:options items="${cityMap }" itemLabel="value" itemValue="key"/>
</form:select> 

------------------------------------------------文件上传-------------------------------------------------

spring-servlet.xml

<!-- 配置文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="defaultEncoding" value="UTF-8"/> 
	<property name="maxUploadSize" value="5242880"/> <!-- 5M -->
	<property name="uploadTempDir" value="upload"/> <!-- 要在WebContent下建立一个upload文件夹 -->
</bean>

uploadUI.jsp

<form action="<c:url value="/upload.html"/>" method="post" enctype="multipart/form-data">
	文件名称:<input type="text" name="name"/><br />
	上传文件:<input type="file" name="file"/><br />
	<input type="submit" value="上传"/>
</form>

UploadController.java

package org.springfuncs.web.controller;

import java.io.File;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/")
public class UploadController {

	@RequestMapping("/uploadUI.html")
	public String uploadUI() {
		return "uploadUI";
	}

	@RequestMapping(value = "/upload.html", method = RequestMethod.POST)
	public String upload(HttpServletRequest request, @RequestParam("name") String name, @RequestParam("file") MultipartFile file) throws Exception {
		if (!file.isEmpty()) {

			// System.out.println("文件的MIME类型:" + file.getContentType());
			// System.out.println("表单的类型为file的name属性名:" + file.getName());
			// System.out.println("原始文件名:" + file.getOriginalFilename());
			// System.out.println("文件大小" + file.getSize());

			String path = request.getSession().getServletContext().getRealPath(File.separator) + "upload" + File.separator + file.getOriginalFilename();
			file.transferTo(new File(path));

			// System.out.println(path); //打印上传路径

			// HttpSession session=request.getSession();
			// session.setAttribute("name", name);
			// session.setAttribute("path", path);

			return "redirect:uploadSuccess.html";
		} else {
			return "redirect:uploadFailure.html";
		}
	}

	@RequestMapping("/uploadSuccess.html")
	public String uploadSuccess() {
		return "uploadSuccess";
	}

	@RequestMapping("/uploadFailure.html")
	public String uploadFailure() {
		return "uploadFailure";
	}
}

uploadSuccess.jsp

上传成功!
<br />
文件名称:<br />
${name }
<br />
图片样张:<br />
<img alt="${name }" src="${path }"/>

uploadFailure.jsp

上传失败!

------------------------------------------------异常处理-------------------------------------------------
spring-servlet.xml

<!-- 映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="defaultErrorView" value="error" />
	<property name="exceptionMappings">
		<props>
			<prop key="java.sql.SQLException">errorDB</prop>
			<prop key="java.lang.RuntimeException">errorRT</prop>
		</props>
	</property>
	<property name="defaultStatusCode" value="500"/>
	<property name="warnLogCategory" value="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"/>
</bean>

error.jsp
发生了未知的错误,请联系管理员。

errorRT.jsp
<%Exception e=(Exception)request.getAttribute("exception");%>
<h1>Exception:</h1>
<%e.printStackTrace(new PrintWriter(out));%>
<hr/>
<%-- ${exception} --%>

-------------------------------------------------单元测试-------------------------------------------------

package junit.test;

import java.util.Date;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import org.springfuncs.domain.User;
import org.springfuncs.service.UserService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:beans.xml" })
@Transactional
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
public class SpringTest {

	@Autowired
	private UserService userService;

	@Test
	public void testRegister() {
		User user = new User();
		user.setUsername("monday");
		user.setPassword("1234");
		user.setEmail("[email protected]");
		user.setBirthday(new Date());
		user.setAge(23);
		userService.register(user);
	}
}

猜你喜欢

转载自1194867672-qq-com.iteye.com/blog/1566968