1、通常情况下,一个Servlet类只负责处理一个请求,若项目中有成百上千个请求需要处理,就需要有成百上千个Servlet类,这样会使得项目中Servlet类的个数暴增;
2、在Servlet3.0版本之前,每一个Servlet都需要在web.xml文件中至少做八行配置信息,配置内容多且繁琐。当Servlet特别多时,web.xml配置量太多,不利于团队开发;
3、当通过客户端提交参数到服务器,通过Servlet进行接收时,无论数据本身是什么格式,在Servlet中一律按照字符串进行接收,后期需要进行类型转换,复杂类型还需要特殊处理,特别麻烦!
String value = request.getParameter(String name);
4、servlet具有容器依赖性,必须放在服务器中运行,不利于单元测试;
Springmvc是spring框架的一个模块,spring和springmvc无需中间整合层整合
Springmvc是一个基于mvc的web框架
提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心
用户发送请求 至 前端控制器(DispatcherServlet);
前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping),处理器映射器(HandlerMapping)找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给DispatcherServlet;
前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器经过适配调用具体的Controller;(Controller–> service --> Dao --> 数据库) Controller执行完成后返回ModelAndView,处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);
提示:Model(模型数据,即Controller处理的结果,Map) View(逻辑视图名,即负责展示结果的JSP页面的名字)
.前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover) 视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面
前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);(默认会存到request域中) 前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。
其中整个过程中需要开发人员编写的部分有Controller、Service、Dao、View;
Spring MVC中的拦截器基于回调机制,可以在目标方法执行之前,先进行业务检测,满足条件则放行,不满足条件则进行拦截,拦截器原理分析如下图所示:
SpringMVC拦截器工作原理 HandlerInterceptor
HandlerInterceptor 拦截器
@Component //spring容器管理对象 public class UserInterceptor implements HandlerInterceptor { @Autowired private JedisCluster jedisCluster; //Spring版本升级 4 必须实现所有的方法 spring 5 只需要重写指定的方法即可. /** * 需求: 拦截/cart开头的所有的请求进行拦截.,并且校验用户是否登录..... * 拦截器选择: preHandler * 如何判断用户是否登录: 1.检查cookie信息 2.检查Redis中是否有记录. * true : 请求应该放行 * false: 请求应该拦截 则配合重定向的语法实现页面跳转到登录页面 使得程序流转起来 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1.判断用户是否登录 检查cookie是否有值 String ticket = CookieUtil.getCookieValue(request,"JT_TICKET"); //2.校验ticket if(!StringUtils.isEmpty(ticket)){ //3.判断redis中是否有值. if(jedisCluster.exists(ticket)){ //4.动态获取json信息 String userJSON = jedisCluster.get(ticket); User user = ObjectMapperUtil.toObj(userJSON,User.class); request.setAttribute("JT_USER",user); return true; } } response.sendRedirect("/user/login.html"); return false; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //销毁数据 request.removeAttribute("JT_USER"); } }WebMvcConfigurer— springmvc 配置类
@Configuration public class MvcConfigurer implements WebMvcConfigurer{ //添加拦截器 @Autowired private UserInterceptor userInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(userInterceptor).addPathPatterns("/cart/**","/order/**"); } }1.页面url标识
2.Controller中的方法
@RequestMapping("/xxx") public void xxx(String name,int age){ }1.页面url标识
2.Controller中的方法
@RequestMapping("/xxx") public void xxx(User user){ } public class User{ //pojo类 private Integer name; private String age; }难点: 属性的重名提交问题… 解决思路: 可以采用对象引用的方式为属性赋值.
<input name="name" value="二郎神" /> <input name="age" value="3000" /> <input name="dog.name" value="哮天犬" /> <input name="dog.age" value="8000" />Controller中的方法
@RequestMapping("/xxx") public void xxx(User user){ } public class Dog{ private String name; private Integer age; } public class User{ private String name; private Integer age; private Dog dog; }@RequestParam 键值对参数,只要前端参数name属性,和后端接收名字的一致,新版本Springboot项目中.注解可省略.
@PathVariable 请求路径参数 ,运用restfun风格{module} 注解不可省略
@RequestBody 完整接收post请求协议的内容,转成pojo集合
当请求发起访问Controller中的方法时,可以通过参数声明,在方法内使用Model。
@RequestMapping("/doorList") public String doorList(Model model){ }Model对象实际上是一个Map集合,例如:往model中添加一个属性
model.addAttribute(String name, Object value);其中,addAttribute方法会将属性保存到request域中,再通过转发将属性数据带到相应的JSP中,通过${}取出并显示。
controller
@RequestMapping("/{itemid}") public String findItemById(@PathVariable Long itemid, Model model){ Item item= dubboItemService.findItemById( itemid); ItemDesc itemDesc= dubboItemService.findItemDescById(itemid); model.addAttribute("item", item); model.addAttribute("itemDesc",itemDesc); return "item"; }item.jsp
在request对象的学习中,通过request对象可以实现请求转发(即资源的跳转)。同样的,springmvc也提供了请求转发的方式,具体实现如下:
@RequestMapping("testForward") public String testForward(){ System.out.println("测试请求转发(forward)..."); return "forward:hello"; } 转发是一次请求,一次响应;转发后地址栏地址没有发生变化(还是访问testForward的地址);转发前后的request和response对象也是同一个。在response对象的学习中,通过response对象可以实现请求重定向(即资源的跳转)。
同样的,springmvc也提供了请求重定向的方式,具体实现如下:
@RequestMapping("testRedirect") public String testRedirect(){ System.out.println("测试请求重定向(redirect)..."); return "redirect:hello"; } 重定向是两次请求,两次响应;重定向后地址栏地址发生了变化(变为转发后的地址);并且在重定向前后,request和response对象不是同一个。