目录
MVC模式
1.早期非MVC模式
早期的Java Web开发中,统一将显示层、控制层、数据层的操作全部交给JSP 或者 JavaBean 来进行处理。如下:
弊端如下:
1.耦合性高,JSP和Java Bean之间严重耦合,Java代码和HTML也耦合在一起 2.要求开发者不仅要掌握Java,还要掌握前端 3.前后端依赖严重,前端需要等待后端完成,后端也依赖前端完成,才能进行有效的测试 4.代码难以复用 2.早期MVC模式
早期的MVC模式采用:Servlet + JSP + Java Bean。如下所示:
- 请求流程
用户的请求首先会到达Servlet,然后根据请求调用相应的Java Bean,并把所有的显示结果交给JSP去完成。
- MVC概念
MVC是一种架构模式,将业务逻辑和页面展示分离,使程序分层、分工合作,既相互独立,又协同合作。
M(Model) 表示模型,模型就是数据(dao,bean)。
通常模型对象负责在数据库中存取数据。
V(View) 表示视图,就是JSP。
通常视图是依据模型数据创建的。
C(Controller) 表示控制器,控制器的作用就是用于处理数据(Model)和视图(View)。
调用业务逻辑产生合适的数据(Model),同时传递数据(Model)给视图层(View)呈现给用户
3.Spring MVC
SpringMVC工作原理
1.spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。
2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.
3.DispatcherServlet请请求提交到目标Controller
4.Controller进行业务逻辑处理后,会返回一个ModelAndView
5.DispatcherServlet查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象
6.视图对象负责渲染返回给客户端。
如下图所示:
导入jar包
在Maven中导入jar包:
<!-- spring-webmvc(包含spring核心包) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.7.RELEASE</version> </dependency>
SpringMVC核心组件
DispatcherServlet
含义 DispatcherServlet是前端控制器 作用 接收请求,响应结果,相当于转发器,降低了组件之间的耦合性
用户发送请求交给DispatcherServlet,DispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户请求,分发到具体对应的Controller,从而获取到需要的业务数据Model。然后Model再通过DispatcherServlet传递给View完成页面的呈现。
实质 Spring MVC通过DispatcherServlet加载Spring容器,实现两者整合 配置:在web.xml中进行servlet配置。要求:在容器启动的时候DispatcherServlet就要被实例化。
<servlet> <servlet-name>xxx</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- contextConfigLocation指定使用spring容器 --> <param-name>contextConfigLocation</param-name> <param-value>classpath:xxx.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>xxx</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
Controller
配置方式如下:
- 通过在spring容器中配置
<!-- controller的配置 --> <bean id="controllerName" class="PackageName.ControllerClassName"></bean>
- 通过注解方式配置
注解方式直接在Controller类上添加@Controller即可。如下:
@Controller public class LoginController { //... }
HandlerMapping
含义 HandlerMapping表示处理器映射器 作用 HandlerMapping负责根据用户请求的URL找到Handler(处理器),帮助DispatcherServlet找到对应的Controller。
SpringMVC提供了多种不同的映射器实现不同的映射方式,例如:配置文件方式、实现接口方式。注解方式等。
配置方式如下:
- 在spring容器中配置
<!-- handlerMapping的配置 --> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mapping"> <props> <!-- key表示请求的url地址,controllerName表示该url地址要找的controller--> <prop key="xxx.do">controllerName</prop> </props> </property> </bean>
- 通过注解方式配置
通过使用@RequestMapping("参数")方式。如下:
@Controller public class LoginController { @RequestMapping("login.do") public ModelAndView login(String uname, String upwd) { ModelAndView mav = new ModelAndView(); System.out.println(uname); System.out.println(upwd); if ("admin".equals(uname) && "123".equals(upwd)) { mav.setViewName("success"); }else { mav.setViewName("login"); } return mav; } }
ViewResolver
含义 ViewResolver表示视图解析器 作用 根据逻辑视图名解析成真正的视图View
ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成具体的页面地址,然后对View进行渲染,将处理结果通过页面展示给用户;SpringMVC提供了很多类型View视图,包括:jstlView、freemarkerView、pdfView、jsp、html等。
配置:在spring容器中配置
<!-- viewResolver的配置 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 拼接出一个jsp地址:/WEB-INF/xxx.jsp --> <!-- prefix表示前缀,suffix表示后缀--> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> </bean>
ModelAndView
ModelAndView是SpringMVC对Model的一种表示形式。SpringMVC中有Model、Map,但是SpringMVC都会将其转化为ModelAndView。
从请求中获取到参数
传递请求到Controller时,如果包含参数,有如下方式获取到传递的参数数据:
- 1.给方法形参添加一个HttpServletRequest
给方法参数传递一个HttpServletRequest,然后从request中获取到参数。
@RequestMapping("toLogin.do") public String login(HttpServletRequest request) { String uname = request.getParameter("uname"); String upwd = request.getParameter("upwd"); if("admin".equals(uname) && "123456".equals(upwd)) { return "success"; // 转发到success.jsp }else { return "jsp/login"; // 转到login.jsp } }
- 2.使用注解
请求中的参数key和方法的形参名字不一样, 需要使用注解,说明请求的中的参数和方法的参数的对应关系。
@RequestMapping("toLogin.do") public String login(@RequestParam("uname")String name, @RequestParam("upwd")String pwd) { if("admin".equals(name) && "123456".equals(pwd)) { return "success"; // 转发到success.jsp }else { return "jsp/login"; // 转到login.jsp } }
- 3.让方法的形参名字和请求中数据的key的名字保持一致
方法的形参名字和请求中数据的key的名字保持一致,那么会自动将请求数据key对应的value值,赋值到对应的形参中。
@RequestMapping("toLogin.do") public String login(String uname, String upwd) { if("admin".equals(uname) && "123456".equals(upwd)) { return "success"; // 转发到success.jsp }else { return "jsp/login"; // 转到login.jsp } }
- 4.方法的形参设置成一个对象
如果请求中数据key和对象的属性名字一样,那么会将传递的数据封装为一个对象。注意:该对象必须有getter和setter方法。
@RequestMapping("abc.do") public String login(User user) { //System.out.println(user.getUname()); //System.out.println(user.getUpwd()); if("admin".equals(user.getUname()) && "123456".equals(user.getUpwd())) { return "success"; // 转发到success.jsp }else { return "jsp/login"; // 转到login.jsp } }
Controller传递数据到JSP页面
1.通过ModelAndView(不推荐)
@RequestMapping("toLogin.do") public ModelAndView login(User user) { ModelAndView mav = new ModelAndView(); Map<String, Object> map = mav.getModel(); if("admin".equals(user.getUname()) && "123456".equals(user.getUpwd())) { map.put("msg", "登录成功"); mav.setViewName("success"); }else { map.put("msg", "登录失败"); mav.setViewName("success"); } return mav; }
2.通过ModelMap
在jsp页面中可以使用el表达式获取到这个参数值。
@RequestMapping("toLogin.do") public String login(User user, ModelMap map) { if("admin".equals(user.getUname()) && "123456".equals(user.getUpwd())) { map.put("msg", "登录 success。。。。。。。。"); return "success"; // 转发到success.jsp }else { map.put("msg", "登录 fail 。。。。。。。。"); return "success"; } }
3.通过Model
在jsp页面中可以使用el表达式获取到这个参数值。
@RequestMapping("toLogin.do") public String login(User user, Model model) { if("admin".equals(user.getUname()) && "123456".equals(user.getUpwd())) { model.addAttribute("msg", "login success,,,,,,,"); return "success"; // 转发到success.jsp }else { model.addAttribute("msg", "login fail,,,,,,,"); return "success"; } }
拦截器
1.使用
- 定义类继承于HandlerInterceptorAdapter
重写其中的方法:
public class FirstInterceptor extends HandlerInterceptorAdapter{ /** * Controller中的方法执行之前,要先访问preHandle方法 * 返回true表示通过请求,返回false表示不通过请求 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle方法被执行"); return false; } /** * 在Controller中的方法执行之后,执行该方法 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle方法被执行"); } /** * 请求处理结束之后,执行该方法 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception { System.out.println("afterCompletion方法被执行"); } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { System.out.println("afterConcurrentHandlingStarted方法被执行"); } }
- 在Spring的容器中进行配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"> <context:component-scan base-package="day4"></context:component-scan> <!-- viewResolver的配置 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 拦截器的配置 --> <mvc:interceptors> <!-- 可以配置多个拦截器 --> <mvc:interceptor> <!-- 匹配需要被拦截的请求路径:/**代表拦截所有的请求 --> <mvc:mapping path="/**"/> <!-- exclude-mapping:表示不被拦截的请求路径,可以配置多个--> <mvc:exclude-mapping path="/user/toLogin.do"/> <mvc:exclude-mapping path="/user/login.do"/> <bean class="day4.FirstInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> </beans>
国际化
1.定义
国际化指的是,一套软件适合所有语言的人使用,根据地区匹配显示对应的语言(中文地区显示中文,英文地区显示英文)。
2.实现国际化步骤
- 1.配置不同语言的属性文件
将页面显示的内容,使用支持国际化的属性文件中的内容显示。如下所示:配置了中文和英文的属性文件:
英文属性文件:message_en_US.properties
welcomeInfo=Welcome to use Student Management Syatem username=user name password=user pwd rember=is rember? login=login loginResult=login result is: success=success fail=fail
中文属性文件:message_zh_CH.properties
welcomeInfo=\u6B22\u8FCE\u4F7F\u7528\u5B66\u751F\u7BA1\u7406\u7CFB\u7EDF username=\u7528\u6237\u540D password=\u5BC6\u7801 rember=\u662F\u5426\u8BB0\u4F4F\u5BC6\u7801\uFF1F login=\u767B\u5F55 loginResult=\u767B\u5F55\u7ED3\u679C\u4E3A success=success fail=fail
- 2.在Spring的xml容器中进行国际化相关配置
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <context:component-scan base-package="day5"></context:component-scan> ... <!-- 国际化相关配置 --> <!-- 规定id只能叫:messageSource --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <!-- name:表示属性名字 value:表示要引用的属性文件的名字 --> <!-- 引入英文配置文件 --> <property name="basename" value="message_en_US"></property> </bean> </beans>
- 3.在JSP页面中引入Spring 标签库,引入属性文件中的key对应的value
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page import="javax.servlet.http.Cookie" %> <!-- 引入Spring标签库 --> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> <!--登录页面--> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>登录页面</title> <link rel="stylesheet" href="css/reset.css" /> </head> <body> <div class="contian"> <div class="disc"><spring:message code="welcomeInfo"></spring:message></div> <div class="cont"> <form action="<%=request.getContextPath() %>/login.do" method="get"> <div class="name_div"> <!-- 用户名 --> <label for="user"><spring:message code="username"></spring:message></label> <input class="int" type="text" name="uname" /> </div> <div class="pwd_div"> <!-- 密码 --> <label for="pwd"><spring:message code="password"></spring:message></label> <input class="int" type="password" name="upwd" /> </div> <div class="pwd_div"> <!-- 是否记住密码 --> <input class="int" type="checkbox" name="remember" value="1" checked="checked"/> <spring:message code="rember"></spring:message> </div> <!-- 登录 --> <input type="submit" value='<spring:message code="login"></spring:message>'></input> </form> </div> </div> </body> </html>
- 4.在Controller的方法里面使用国际化传递参数
需要使用到ResourceBundleMessageSource类,用于获取到属性文件中的key对应的value值。
@Controller public class LoginController { //可以获取到属性文件中的Key @Resource private ResourceBundleMessageSource messageSource; @RequestMapping("toLogin.do") public String toLogin() { return "i18n_login"; } /** * 在方法中使用国际化,从配置文件中读取key * @param model * @param uname * @param upwd * @param locale * @return */ @RequestMapping("login.do") public String login(Model model, String uname, String upwd, Locale locale) { if ("admin".equals(uname) && "123".equals(upwd)) { String success = messageSource.getMessage("success", null, locale); model.addAttribute("msg", success); }else { String fail = messageSource.getMessage("fail", null, locale); model.addAttribute("msg", fail); } return "result"; } }
3.运行结果
使用英文配置文件,登录页面如下所示:
跳转后的结果JSP页面如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <spring:message code="loginResult"></spring:message>:${msg } </body> </html>
输入正确的账号密码后结果页面显示如下:
参考:https://blog.csdn.net/luciferlongxu/article/details/80460580