MVC框架,它解决WEB开发中常见的问题(参数接收、文件上传、表单验证、国际化、等等),而且使用简单,与Spring无缝集成。
Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架 (更安全,性能更好,更简单)。
支持 RESTful风格的 URL 请求 。
采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。
SpringMVC和Struts2对比:
DispatcherServlet.properties文件中默认已经配置了
处理器映射器/配置处理器适配器/配置视图解析器
Spring MVC前端控制器
web.xml
spring mvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:mvc.xml
1
spring mvc
/
配置分支控制器
mvc.xml
处理请求断电分支控制器
HelloController
public class HelloController implements Controller{
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
System.out.println("...Hello Controller...");
//请求作用域中共享数据msg并且转发到hello.jsp
ModelAndView mView = new ModelAndView();
mView.addObject("msg", "Dusk");
mView.setViewName("/WEB-INF/views/hello.jsp");
return mView;
}
}
SpringMVC流程:
涉及组件分析:
前端控制器DispatcherServlet(不需要程序员开发),由框架提供,在web.xml中配置。
作用:接收请求,响应结果,相当于转发器,中央处理器。
处理器映射器HandlerMapping(不需要程序员开发),由框架提供。
作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
处理器适配器HandlerAdapter(不需要程序员开发),由框架提供。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
处理器Handler(也称之为Controller,需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
视图解析器ViewResolver(不需要程序员开发),由框架提供
作用:进行视图解析,把逻辑视图名解析成真正的物理视图。
SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、pdfView等。
视图View(需要工程师开发)
作用:把数据展现给用户的页面
View是一个接口,实现类支持不同的View技术(jsp、freemarker等)
我们这样的配置有这样一个问题:
在Web根路径添加index.html,然后不能访问,原因是什么呢?
为什么此时在配置前端控制器的写成 / 就不行呢?
原因:
Tomcat中处理静态资源访问的servlet(default)的映射路径为/.
在启动项目的时候,在Tomcat中的web.xml是先加载的,项目的web.xml是后加载的,如果配置了相同的映射路径,后面的会覆盖前者.
也就是说,SpringMVC中的DispatcherServlet的映射路径覆盖了Tomcat默认对静态资源的处理的路径。
如果SpringMVC要配置为/,那么就得设置Dispatcherservlet对静态资源进行支持。
解决方案:需要在SpringMVC的配置文件中添加对静态资源的访问
将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 Tomcat默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
/和/*的区别:
Java EE应用程序分为三层:
表现层(Web) @Controller
业务逻辑层(Service) @Service
数据持久层(DAO) @Resposotory
其他组件使用通用注解 @Component
注意:
SpringMVC注解的解析器:
会自动注册RequestMappingHandlerMapping/RequestMappingHandlerAdapter/ExceptionHandlerExceptionResolver三个bean
@RequestMapping(value="/list",method=RequestMethod.POST)
@Controller
@RequestMapping("dusk")
public class HelloController{
@RequestMapping("Hello")
public ModelAndView test1() {
System.out.println("HelloAnnoController.test1()");
return null;
}
}
request.getRequestDispatcher("页面路径").forward(request, response);
response.sendRedirect("url");
mvc.xml配置视图解析器
如:返回视图名称为resp, 则完整物理视图地址为:/WEB-INF/views/resp.jsp
返回String类型和共享数据
返回对象类型和共享数据
这种方式没有返回视图名称,默认使用了被访问的RequestMapping的值作为逻辑视图名称
@ModelAttribute作用如下:
类RespController
@Controller
public class RespController {
@RequestMapping("test4")
@ModelAttribute("u")
public User handler() {
//此时返回url作为逻辑视图名称:resp/test4
System.out.println("====");
return new User();
}
/**
* 返回逻辑视图名称和共享数据
* @param model
* @return
*/
public String test3(Model model) {
//通过传入的模型对象来共享数据
model.addAttribute("msg","Dusk");
model.addAttribute("真");
//取消默认的前缀和后缀
return "redirect:/hello.jsp";//逻辑视图名称
}
/**
* 返回ModelAndView类型和共享数据
* @return
*/
@RequestMapping("test2")
public ModelAndView test2() {
ModelAndView mView = new ModelAndView();
//设置模型对象
mView.addObject("msg","真.西门");
//默认key为数据类型首字母小写,既${string}
mView.addObject("鸟");
//设置视图名称
mView.setViewName("hello");
return mView;
}
/**
* 返回void类型和共享数据
* 使用出入的servlet的方式
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@RequestMapping("test1")
public void test1(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
//这里操作和servlet的操作一样
req.setAttribute("msg", "Dusk");
req.getRequestDispatcher("hello").forward(req, resp);
}
}
多对象封装传参
把表单中的数据封装到多个对象中去.
由@InitBinder标识的方法,可以对WebDataBinder对象进行初始化
WebDataBinder是DataBinder的子类,用于完成由请求参数到JavaBean的属性绑定
@InitBinder方法不能有返回值,它必须声明为void
@InitBinder方法的参数通常是WebDataBinder
当需要把表单数据封装到多个对象中去的时候,如果各个对象中都有相同的属性
如name. 此时请求参数name就不清楚到底该封装到哪一个对象中去。
而默认情况下SpringMVC不支持 对象名.属性名 这种传参方式的。
RESTfull风格参数
RESTful是一种软件架构风格,严格上说是一种编码风格,其充分利用 HTTP 协议本身语义从而提供了一组设计原则和约束条件
主要用于客户端和服务器交互类的软件,该风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
在后台,RequestMapping标签后,可以用{参数名}方式传参,同时需要在形参前加注解@PathVarable
解决中文乱码问题
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncodingFilter
/*
mvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:mvc.xml
mvc
*.do
Employee类
@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private String name;
private Integer age;
}
User
@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name = "dusk" ;
private Integer age = 12;
private List hobby;
}
req.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
注值
test 多对象注值
test List<>注值
test checkbox提交数组
test对象注入
test简单类型注入
date.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
日期
test3
GetData
//控制器增强
@Controller
@RequestMapping("getData")
public class GetData {
/*@InitBinder
public void initBinderDateType(WebDataBinder binder){
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd");
binder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,true));
}*/
@RequestMapping("test3")
public ModelAndView test3(Date date){
System.out.println("日期: "+date);
return null;
}
/*@RequestMapping("test2")
public ModelAndView test2(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){
System.out.println("日期格式: " + date);
return null;
}*/
@RequestMapping("test1")
public ModelAndView test1(User u){
ModelAndView mv = new ModelAndView();
mv.setViewName("req");
return mv;
}
}
或是使用类
CtrlAdvice
@ControllerAdvice
public class CtrlAdvice {
@InitBinder
public void initBinderDateType(WebDataBinder binder){
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd");
binder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,true));
}
}
配置文件上传解析器:bean的名字是固定的
使用Spring表达式 #{1024*1024}
上传
upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
图片上传
下载
download.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
下载
下载
FileController控制器
@Controller
public class FileController {
@RequestMapping("download")
public ModelAndView download(String filename, HttpServletRequest req, HttpServletResponse resp) throws IOException {
String dir = req.getServletContext().getRealPath("/fileupload");
//设置下载的相应头信息
resp.setContentType("application/x-msdownload");//一下载的方式打开
resp.setHeader("Content-Disposition","attachment;filename="+filename);//设置下载文件的名称
ServletOutputStream out = resp.getOutputStream();
System.out.println(dir + filename);
Files.copy(Paths.get(dir,filename),out);
return null;
}
@RequestMapping("upload")
public ModelAndView upload(MultipartFile headImg, HttpServletRequest req) throws IOException {
//获取文件的真实名称
String filename = headImg.getOriginalFilename();
//获取上传文件的流数据
InputStream in = headImg.getInputStream();
String dir = req.getServletContext().getRealPath("/fileupload");
Files.copy(in, Paths.get(dir,filename));
return null;
}
}
Spring MVC 的拦截器类似于Servlet 开发中的过滤器Filter,用于对Controller进行预处理和后处理。
使用SpringMVC拦截器步骤:
拦截器方法的执行时机:
登录控制器LoginController
@Controller
public class LoginController {
@RequestMapping("login")
public String login(String username,String password,HttpSession session){
if ("admin".equals(username) && "123".equals(password)){
session.setAttribute("USER_IN_SESSION",username);
return "forward:/user/list.do";
}
return "forward:/login.jsp";
}
}
登录拦截器CheckLoginInterceptor
public class CheckLoginInterceptor extends HandlerInterceptorAdapter{
/*在controller方法值前做拦截,返回true表示放行*/
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,Object handler) throws IOException {
//从session中获取当前登录成功的对象
Object user = request.getSession().getAttribute("USER_IN_SESSION");
//判断是否为null
if (user == null) {
//没有登录,返回到登录界面
response.sendRedirect("/login.jsp");
return false;
}
return true;//放行
}
}
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录
配置拦截器mvc.xml
web.xml : /
mvc.xml:
web.xml : *.do
request.getRequestDispatcher("页面路径").forward(request, response);
ModelAndView mv = new ....
mv.addObject(key, value)
public String xxx(Model model){
model.addAttribute(key, value);
}
4:返回对象类型和共享数据
public 对象 xxx(){....}
public xxx xx(String xx, Integer xx)
public xxx xx(User xx)
public xxx xx(Long[] xx)