tips:为方便阅读,我将目录放到最后,可使用CSDN右侧工具栏点击目录查看。
就是Spring的一个模块,Spring框架中提供的一个表示层的解决方案。用来替换Servlet。Spring3.0出现,之前用struts比较流行。
MVC模型:是一种架构的新模式,本身不引入新的功能,只是帮助我们将开发的结构组织的更加合理。使展示与模型分离,流程逻辑控制、业务逻辑调用与展示逻辑分离。
model(模型):数据模型,包含要展示的数据和业务。
View(视图):用户界面,在界面上展示模型数据。
Controller(控制器):起调度作用,接收用户请求,调用业务处理请求,共享数据模型并跳转界面。
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
public class Mycontroler implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","hello SpringMVC");
mv.setViewName("/msg.jsp");
return mv;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="/my.do" class="com.woniuxy.springmvc.Mycontroler">bean>
beans>
根据请求的url查找Handler(处理器),可以通过XML和注解方式来映射。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean id="/my.do" class="com.woniuxy.springmvc.Mycontroler"/>
<bean id="/your.do" class="com.woniuxy.springmvc.Mycontroler"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/my.do" value-ref="myController">entry>
<entry key="/first.do" value-ref="myController">entry>
map>
property>
bean>
<bean id="myController" class="com.woniuxy.springmvc.Mycontroler"/>
按照特定规则(handlerAdapter要求的规则)去执行Handler,且不同的接口可以统一工作。
public class Mycontroler implements Controller {
@Override
//有返回值
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","hello SpringMVC");
mv.setViewName("/msg.jsp");
return mv;
}
}
public class Mycontroler implements HttpRequestHandler {
@Override
//无返回值
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("msg", "mymsg");
request.getRequestDispatcher("/msg.jsp").forward(request, response);
}
}
可以定义处理请求的方式,例如post。
public class Mycontroler extends AbstractController {
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","mysss");
mv.setViewName("/msg.jsp");
return mv;
}
}
xml配置
<bean id="myController" class="com.woniuxy.springmvc.Mycontroler">
<property name="SupportedMethods" value="POST"/>
bean>
多方法控制器。
public class Mycontroler extends MultiActionController {
public ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
public ModelAndView doSecend(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doSecend");
mv.setViewName("/msg.jsp");
return mv;
}
public ModelAndView doThird(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doThird");
mv.setViewName("/msg.jsp");
return mv;
}
}
配置文件:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/*.do" value-ref="myController">entry>
map>
property>
bean>
<bean id="myController" class="com.woniuxy.springmvc.Mycontroler">
bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/*.do" value-ref="myController">entry>
map>
property>
bean>
<bean id="PropertiesMethodNameResolver"
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/first.do">doFirstprop>
<prop key="/secend.do">doSecendprop>
<prop key="/third.do">doThirdprop>
props>
property>
bean>
<bean id="myController" class="com.woniuxy.springmvc.Mycontroler">
<property name="methodNameResolver" ref="PropertiesMethodNameResolver"/>
bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/my.do" value-ref="myController">entry>
map>
property>
bean>
<bean id="ParameterMethodNameResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName" value="method"/>
bean>
<bean id="myController" class="com.woniuxy.springmvc.Mycontroler">
<property name="methodNameResolver" ref="ParameterMethodNameResolver"/>
bean>
注意:无ID
注意:配置了BeanNameViewResolver后,要将默认的视图解析器也配上。
<context:component-scan base-package="com.woniuxy.springmvc"/>
controller
@Controller
public class Mycontroler{
@RequestMapping("/my.do")//这个注解就相当于映射器
protected ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
@RequestMapping({"/your.do","he.do"})//多路径映射同一个处理器,用数组
protected ModelAndView doSecend(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doSecend");
mv.setViewName("/msg.jsp");
return mv;
}
}
controller
@Controller
@RequestMapping("/test")//浏览器访问方式变为../test/first.do
public class Mycontroler{
@RequestMapping("/my.do")//这个注解就相当于映射器
protected ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
controller
@Controller
public class Mycontroler{
@RequestMapping("/my*.do")//my后面任意
protected ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
@RequestMapping("/*your.do")//your前面任意
protected ModelAndView doSecend(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doSecend");
mv.setViewName("/msg.jsp");
return mv;
}
@RequestMapping("/*/third.do")// /名称任意/third.do
protected ModelAndView doThird(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doSecend");
mv.setViewName("/msg.jsp");
return mv;
}
}
controller
@Controller
public class Mycontroler{
//仅支持post请求
@RequestMapping(value="/my*.do",method=RequestMethod.POST)
protected ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
@Controller
public class Mycontroler{
//提交的请求参数中必须要有name和age
@RequestMapping(value="/first*.do",params= {"name","age"})
protected ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
//提交的请求参数中必须要有name,不能有age
@RequestMapping(value="/secend*.do",params= {"name","!age"})
protected ModelAndView doSecend(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
//提交的请求参数中必须要有name和age,且name的值必须为zs.
@RequestMapping(value="/third*.do",params= {"name=zs","age"})
protected ModelAndView doThird(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
页面:
<body>
<form action="/springmvc-01-annotation/first.do" methos="get">
<input type="text" name="name" />
<input type="text" name="age" />
<input type="submit" value="ok">
form>
body>
controller:
@Controller
public class Mycontroler{
//单个参数接收,处理器方法的参数名和表单的name名一致
@RequestMapping(value="/first.do")
protected ModelAndView doFirst(String name,int age){
System.out.println("name="+name);
System.out.println("age="+age);
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
<init-param>
<param-name>forceEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
@Controller
public class Mycontroler{
//当表单元素的name和方法参数名不相同的时候,使用@RequestParam注解
@RequestMapping(value="/first.do")
protected ModelAndView doFirst(@RequestParam("sname") String name,
@RequestParam("sage") int age){
System.out.println("name="+name);
System.out.println("age="+age);
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
@Controller
public class Mycontroler{
@RequestMapping(value="/first.do")
protected ModelAndView doFirst(Student student){
System.out.println(student);
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
<body>
<form action="/springmvc-01-annotation/first.do" method="post">
<input type="text" name="student.sname">
<input type="text" name="student.age">
<input type="submit" value="ok">
form>
body>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<context:component-scan base-package="com.woniuxy.springmvc"/>
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
@Controller
@RequestMapping("/test")
public class Mycontroler{
//id相当于占位符
@RequestMapping(value="/delete/{id}")
protected ModelAndView doFirst(@PathVariable("id") String id){
System.out.println(id);
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
Model是数据,View视图,两个都需要就使用这个返回值
@RequestMapping(value="/secend.do")
protected ModelAndView doSecend(){
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
返回的字符串作为视图ID(JstlView(使用它必须要导入jstl的jar包),RedirectView)
//返回的字符串为视图ID。
@RequestMapping(value="/third.do")
protected String doThird(){
System.out.println("go go go");
return "mymsg";
}
//转发:默认的资源视图解析器,前缀后缀不起作用
@RequestMapping(value="/third.do")
protected String doThird(){
System.out.println("go go go");
return "forward:/test.jsp";
}
//重定向:默认的资源视图解析器,前缀后缀不起作用
@RequestMapping(value="/third1.do")
protected String doThird1(){
System.out.println("go go go");
return "redirect:/test.jsp";
}
使用我们原来学习的servlet来处理即可。
@RequestMapping(value="/third.do")
protected void doThird(HttpServletRequest req,HttpServletResponse resp)
throws ServletException, IOException{
req.getRequestDispatcher("/msg.jsp").forward(req, resp);
}
使用Jackson,实现Ajax响应。
<mvc:annotation-driven/>
@Controller
@RequestMapping("/test")
public class Mycontroler{
@RequestMapping(value="/first.do")
@ResponseBody//将返回的对象注入到响应体中
protected Object doFirst(){
System.out.println("执行处理");
return new Student("lzff",11);
}
}
4.页面发送AJAX请求
<script type="text/javascript">
$(function(){
$("#btnok").click(function(){
$.post("/springmvc-01-annotation/test/first.do",
null,
function(data){
alert(data.sname);
alert(data.age);
})
})
})
</script>
注意:注解驱动一定要配置,框架底层才能自动创建相关的对象。使用Jackson,AJAX不用将获得的数据在eval化。直接使用即可。
在Serverlet中处理异常有两种方式,try-catcah或者是在web.xml中配置错误页面。在SpringMVC中,
在Spring配置文件中注册异常处理器,配上相关的属性即可。
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="/errors/error.jsp" />
<property name="exceptionAttribute" value="ex" />
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">/errors/nullpoint.jspprop>
<prop key="java.lang.ArithmeticException">/errors/aritherror.jspprop>
props>
property>
bean>
添加错误页面,使用${ex.message}获取异常信息
缺点:该异常处理只能做页面跳转,不能执行其他操作,例如想在错误的时候执行保存错误日志等。
自定义异常处理器,可以用注解实现,也可以用配置实现。视使用场景不同自行选择。
public class MyHandlerExceptionResolver implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
ModelAndView mv=new ModelAndView();
mv.addObject("ex",ex);
if(ex instanceof ArithmeticException) {
System.out.println("记录产生ArithmeticException异常");
mv.setViewName("/errors/aritherror.jsp");
}else if(ex instanceof NullPointerException) {
System.out.println("记录产生NullPointerException异常");
mv.setViewName("/errors/nullpoint.jsp");
}else{
System.out.println("Exception记录日志");
mv.setViewName("/errors/error.jsp");
}
return mv;
}
}
<bean class="com.woniuxy.springmvc.MyHandlerExceptionResolver">bean>
使用注解实现异常处理只需在上例基础做如下修改:
@RequestMapping(value="/third.do")
protected ModelAndView doThird(){
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doSecend");
mv.setViewName("/msg.jsp");
return mv;
}
@ExceptionHandler
public ModelAndView resolveException(Exception ex) {
ModelAndView mv=new ModelAndView();
mv.addObject("ex",ex);
if(ex instanceof ArithmeticException) {
System.out.println("记录产生ArithmeticException异常");
mv.setViewName("/errors/aritherror.jsp");
}else if(ex instanceof NullPointerException) {
System.out.println("记录产生NullPointerException异常");
mv.setViewName("/errors/nullpoint.jsp");
}else{
System.out.println("Exception记录日志");
mv.setViewName("/errors/error.jsp");
}
return mv;
}
<body>
<form action="${pageContext.request.contextPath}/test/first.do">
<input type="text" name="name" />br>
<input type="text" name="birthdate" />br>
<input type="submit" value="OK">
form>
body>
@Controller
@RequestMapping("/test")
public class Mycontroler{
//页面传过来的 birthdate应该是个string类型,而我们想转换成date类型,MVC不会自动转换, 此时会出400或500错误
@RequestMapping(value="/first.do")
protected ModelAndView doFirst(String name,Date birthdate){
System.out.println("name"+name);
System.out.println("birthdate"+birthdate);
ModelAndView mv=new ModelAndView();
mv.addObject("msg","doFirst");
mv.setViewName("/msg.jsp");
return mv;
}
}
public class DateConvert implements Converter<String, Date>{
@Override
public Date convert(String source) {
if(source!=null && !source.trim().equals("")) {
DateFormat df=new SimpleDateFormat("yyyy-MM-dd");
try {
return df.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
<context:component-scan base-package="com.woniuxy.springmvc"/>
<bean id="dateConvert" class="com.woniuxy.convert.DateConvert"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="dateConvert"/>
set>
property>
bean>
<mvc:annotation-driven conversion-service="conversionService"/>
@InitBinder//添加initBinder注解
public void initBinder(WebDataBinder binder) {
DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
//注册原类型和目标类型的转换格式
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
日期转换使用注解缺点和自定义异常使用注解的缺点相同,只有该处理器类能够使用。
使用hibernate-validator验证插件。
<context:component-scan base-package="com.woniuxy.springmvc"/>
<bean id="localValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator "/>
bean>
<mvc:annotation-driven validator="localValidator"/>
public class Student {
@NotEmpty(message="姓名不能为空")//对象为空
@Size(min=3,max=5,message="长度{min}--{max}之间")
private String name;
@NotNull(message="成绩不能为空")
@Min(value=0,message="不能小于{value}")
@Max(value=100,message="不能大于{value}")
private Double score;
@NotEmpty(message="手机号不能为空")
@Pattern(regexp="^1[38]\\d{9}$",message="手机号格式错误")
private String mobile;
@NotNull(message="生日不能为空")
@DateTimeFormat(pattern="^\\d{4}-\\d{2}-\\d{2}$")
private Date birthdate;
@NotEmpty(message="邮箱不能为空")
@Email(message="邮箱格式错误")
private String email;
}
@RequestMapping(value="/first.do")
//BindingResult将验证的错误信息记录
protected ModelAndView doFirst(@Validated Student student,BindingResult br){
ModelAndView mv=new ModelAndView();
int count =br.getErrorCount();//获取验证错误条数
if(count>0) {
//获取错误消息字段
FieldError fieldErrorName = br.getFieldError("name");
FieldError fieldErrorScore = br.getFieldError("score");
FieldError fieldErrorMobile = br.getFieldError("mobile");
FieldError fieldErrorBirthdate = br.getFieldError("birthdate");
FieldError fieldErrorEmail = br.getFieldError("email");
if(fieldErrorName!=null) {
mv.addObject("errorname", fieldErrorName.getDefaultMessage());
}
if(fieldErrorScore!=null) {
mv.addObject("errorscore", fieldErrorScore.getDefaultMessage());
}
if(fieldErrorMobile!=null) {
mv.addObject("errormobile", fieldErrorMobile.getDefaultMessage());
}
if(fieldErrorBirthdate!=null) {
mv.addObject("errorbirthdate", fieldErrorBirthdate.getDefaultMessage());
}
if(fieldErrorEmail!=null) {
mv.addObject("erroremail", fieldErrorEmail.getDefaultMessage());
}
mv.setViewName("/index.jsp");
return mv;
}
mv.addObject("msg","登陆成功");
mv.setViewName("/msg.jsp");
return mv;
}
<body>
<form action="/springmvc-01-fileupload/test/first.do" method="post"
enctype="multipart/form-data">
<input type="file" name="newImg">
<input type="submit" value="ok">
form>
body>
@RequestMapping("/test")
public class Mycontroler{
@RequestMapping(value="/first.do")
@ResponseBody//将返回的对象注入到响应体中
//MultipartFile对象名必须和表单元素name一致
protected ModelAndView doFirst(MultipartFile newImg,HttpServletRequest request) throws IllegalStateException, IOException{
if(newImg!=null) {
//文件打散,UUID取前两位
//将虚拟路径转换成绝对路径
String path=request.getServletContext().getRealPath("/img");
//获取文件名字
String fileName=newImg.getOriginalFilename();
//获取IO流
File file=new File(path,fileName);
//上传
newImg.transferTo(file);
}
ModelAndView mv=new ModelAndView();
mv.setViewName("/msg.jsp");
return mv;
}
}
<mvc:annotation-driven/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">bean>
拦截器和Servlet的过滤器类似,用来拦截请求。不同的是, 拦截器不会拦截页面,只会拦截请求。