SpringMVC
发表于|更新于
|字数总计:2.1k|阅读时长:7分钟|阅读量:
SpringMVC的设计模式
单例模式
单例模式是常见的一种设计模式,确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。单例模式满足如下条件:
只能有一个实例;
它必须自行创建这个实例;
它须自行向整个系统提供这个实例。
单例模式根据创建实例的时机分为懒汉模式和饿汉模式。
懒汉模式
所谓懒汉模式是指在类加载的时候不需要创建实例,采用延迟加载的方式。在运行时调用时才创建实例。使用“时间换空间”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if(instance == null) instance = new Singleton(); return instance; } }
|
这种方式保证了延迟加载的特性,从线程安全的角度上来说,懒汉式是不安全的,在多线程下无法正常工作。,假设,现在有线程A和线程B同时去调用getInstance方法,就可能出现线程并发的情况。解决方法就是线程同步,使用synchronized关键字解决。
1 2 3 4 5
| public static synchronized Singleton getInstance() { if(instance == null) instance = new Singleton(); return instance; }
|
饿汉模式
所谓饿汉模式是指在类加载的时候就完成了初始化操作,所以类加载的速度较慢。但是获取速度很快,使用“空间换时间”。由于饿汉模式在初始化已经自行实例化,因此不存在线程安全问题。
1 2 3 4 5 6 7 8 9 10
| public class Singleton { private static Singleton instance = private Singleton() { } public static Singleton getInstance() { return instance; }
|
在实际应用中可能需要使用单例模式创建对象,又需要延迟加载提高性能,并且还要解决线程安全的问题。可以使用静态内部类的方式实现。
静态内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Singleton { private static Singleton instance = null; private Singleton() { } public static class SingletonHelper{ private static final Singleton INSTANCE=new Singleton(); } public static Singleton getInstance() { instance=SingletonHelper.INSTANCE; return instance; }
|
Singleton类被加载后不一定被初始化,只有当getInstance方法被主调用时,SingletonHelper类才被加载。既满足了延迟加载的特性,又满足了线程安全。
SpringMVC-Controller的单例管理
SpringMVC的Contoller类是设计为单例模式的,不需要每次都创建实例。主要是基于性能的考虑。所以,一般不要在Controller中定义成员变量,否则会导致严重的线程安全以及性能问题。可能出现多次请求看到相同的数据。因为属性在内存只有一份数据。可以使用@Scope(“prototype”)将Controller变成多例的来解决,但是这种方式效率低,也违背了SpringMVC设计的初衷。通常情况下,在Contoller中只有业务类作为成员变量,但是业务类通常是接口,只有方法,没有属性,所以不存在线程安全的问题。
配置文件
在工程的类路径即resources
目录下创建 SpringMVC 的配置文件 springmvc.xml
。该文件名可以任意命名。推荐使用springmvc.xml
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<context:component-scan base-package="io.peng"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property> </bean>
|
请求规则
指定post提交,method
属性
1 2 3 4
| @RequestMapping(value = "/main",method = RequestMethod.POST) public String one() { return "main"; }
|
序号 |
请求方式 |
提交方式 |
1 |
表单请求 |
默认get,可以指定post |
2 |
ajax请求 |
默认get,可以指定post |
3 |
地址栏请求 |
get请求 |
4 |
超链接 |
get请求 |
5 |
src资源路劲请求 |
get请求 |
四种跳转方式
默认的跳转是请求转发,直接跳转到jsp页面展示,还可以使用框架提供的关键字redirect,进行一个重定向操作,包括重定向页面和重定向action,使用框架提供的关键字forward,进行服务器内部转发操作,包括转发页面和转发action。当使用redirect和forward关键字时,视图解析器就无效了。
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Controller @RequestMapping("/one") public class One { @RequestMapping("/requestpage") public String jump1(){ return "main"; }
@RequestMapping("/requestController") public String requestController(){ System.out.println("one........."); return "forward:/two/demo.action"; }
@RequestMapping("/redirectpage") public String redirectpage(){ return "redirect:/main.jsp"; }
@RequestMapping("/redirectcontroller") public String redirectcontroller(){ return "redirect:/two/demo.action"; } }
|
支持的默认参数类型
这些类型只要写在方法参数中就可以使用了。
1)HttpServletRequest
对象
2)HttpServletResponse
对象
3)HttpSession
对象
4)Model/ModelMap
对象
5)Map<String,Object>
对象
注意Model,Map,ModelMap都使用的是request请求作用域,意味着只能是请求转发后,页面才可以得到值
拦截器
使用场景
1、日志记录:记录请求信息的日志
2、权限检查,如登录检查
3、性能检测:检测方法的执行时间
实现的两种方式
继承HandlerInterceptorAdapter的父类
实现HandlerInterceptor接口
而HandlerInterceptor接口中含有三个方法
- preHandle
该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。
- postHandle
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
- afterCompletion
当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。
以下示例重写HandlerInterceptorAdapter的preHandle方法,实现网站访问权限的过滤功能。
(1)编写拦截器功能类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class SecurityInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { User user=(User) request.getSession().getAttribute("user"); if(user==null){ String logintUrl=request.getContextPath()+"/"+"login"; String returnUrl=request.getServletPath(); response.sendRedirect(logintUrl+"?returnUrl="+returnUrl); return false; } return true; } }
|
只有登录用户才能进入后台管理,并且记录下用户请求的当期路径,然后登录成功时自动进入之前请求的代码
自动跳转到之前请求的URL
UserController的核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @RequestMapping(value="/login",method=RequestMethod.GET) public String login() { return "login"; } @RequestMapping(value="/login",method=RequestMethod.POST) public String login(String username, String password, HttpSession session,String returnUrl, Model model) { User user=userBiz.checkLogin(username, password); if(user!=null) { session.setAttribute("user",user); if(returnUrl!=null) { return "redirect:"+returnUrl; } else { return "redirect:/movie/list"; } } else { model.addAttribute("error","用户名或者密码错误"); return "login"; } }
|
配置拦截器类
1 2 3 4 5 6
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/movie/**" /> <bean class="com.mycinema.web.interceptor.SecurityInterceptor" /> </mvc:interceptor> </mvc:interceptors>
|
根据配置,当请求路径为/movie/下任意目录(**
代表目录,而*
代表文件)路径时,会应用SecurityInterceptor
拦截器。