三层架构:
开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器服务器。
在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层
表现层:
实际就是web层,接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web层,web需要接收http请求,完成响应。
表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
表现层的设计一般都使用MVC模型。(MVC是表现层的设计模型,和其他层没有关系)
业务层:
常说的service层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层。
业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。
(也就是我们说的,事务应该放到业务层来控制)
持久层:
常说的dao层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。
通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。
MVC模型:
Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,
用于设计创建Web应用程序表现出的模式
Model(模型): 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
View(视图): 通常指的就是我们的jsp或者html。作用一般就是展示数据的。 通常视图是依据模型数据创建的。
Controller(控制器): 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。
Controller例子:
我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。 这时候表单输入要求年龄必须是1~100之间的整数。
姓名和性别不能为空。并且把数据填充到模型之中。 此时除了js的校验之外,服务器端也应该有数据准确性的校验,那么校验
就是控制器的该做的。 当校验失败后,由控制器负责把错误页面展示给使用者。 如果校验成功,也是控制器负责把数据填充到
模型,并且调用业务层实现完整的业务需求。
SpringMVC:
SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于 Spring FrameWork 的后续产品,
已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的
MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他MVC开发框架,
如Struts1(现在一般不用),Struts2等。
SpringMVC已经成为目前最主流的 MVC 框架之一,并且随着Spring3.0的发布
,全面超越 Struts2,成为最优秀的 MVC 框架。
它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实
现任何接口。同时它还支持RESTful编程风格的请求。
解析:RESTful编程风格:
基于Rest理念的一套开发风格,以URL方式进行资源的传递,作为用户交互的入口. 四种请求方式:get post put delete restful 风格只返回json 和xml数据: 1、get请求(常用)—> 对应查询操作 2、post请求(常用)—> 对应新增操作 3、put请求 —> 对应修改操作 4、delete请求 —> 对应删除操作 例子: 1)http://localhost:8080/delete?id=1 RestFUL风格: 1)http://localhost:8080/delete/1
SpingMVC在三层架构的位置
入门实列:
新建maven工程,下载jar包并导入:
spring-web 和spring-webmvc是spring-mvc的jar包
在web.xml配置核心控制器:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!-- 配置sping-mvc的核心控制器--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <!-- 定义servlet的对象创建时间点:应用加载时创建,取值只能时非零的整数,表示启动顺序--> <load-on-startup>1</load-on-startup> </servlet> <!-- 如果没有定义初始化配置文件名字,spring直接会找web-inf下的servlet-name-servler.xml文件--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
此例子不配就是找springmvc-servlet.xml
下面时配置springmvc配置文件的
创建spring-mvc的配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <!-- 定义包的扫描 配置创建Spring容器要扫描的包--> <context:component-scan base-package="com.quan"></context:component-scan> <!-- 定义资源视图,配置视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
@Controller public class indexController { @RequestMapping("/done") public void done(){ System.out.println("okok"); } @RequestMapping("/indexxx") public String index(){ return "index"; } }
需要编写index.jsp文件
测试,需要往工程里面加载tomcat
实例流程分析:
1tomcat启动:加载应用的web.xml
2实例化并初始化Servlet
3加载springmvc的配置文件创建spring容器,根据配置初始化容器中的对象
4客户端发起请求
5请求到达前端控制器Controller
6截取请求的动作名称,并从@RequestMapping中找到匹配的
7找到后,执行控制器中的方法
8方法如果有返回值,根据返回值通过InternalResouceViewResolver找到响应结果的视图
9响应浏览器,展示结果
注意:
浏览器发送请求,被DispatherServlet捕获,该Servlet并不处理请求,而是把请求转发出去。转发的路径是根据请求URL
匹配@RequestMapping中的内容
解析:
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处
理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping 处理器映射器:
HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,
例如:配置文件方式,实现接口方式,注解方式等。
Handler 处理器:
是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler。由Handler对具体的
用户请求进行处理。
HandlerAdapte 处理器适配器:
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
View Resolver 视图解析器:
负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图
对象,最后对View进行渲染将处理结果通过页面展示给用户。
View视图
SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。
我们最常用的视图就是jsp。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,
需要由程序员根据业务需求开发具体的页面。
在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
通过<mvc:annotation-driven>实现处理器和适配器的配置
<mvc:annotation-driven>自动加载RequestMappingHandlerMapping(处理映射器)和
RequestMappingHandlerAdapter(处理适配器)
RequestMapping注解:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping {
作用:
用于建立请求URL和处理请求方法之间的对应关系。
可以出现的位置;
类:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录
可以实现模块化管理:
账户模块: /account/add /account/delete 订单模块: /order/add /order/update /order/delete
方法:请求URL的第二级访问目录。
属性:
value:用于指定请求的URL。它和path属性的作用是一样的。
method:用于指定请求的方式。
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样。
例子;
@RequestMapping(value = "login",params = {"name","age"})
请求参数必须有name 和age
method属性:
可以取的值为:
public enum RequestMethod { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE; private RequestMethod() { } }
@RequestMapping(value = "login",params = {"name","age"},method = RequestMethod.DELETE )
请求参数的绑定
使用要求:
如果是基本类型或者String类型: 要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是POJO类型,或者它的关联对象: 要求表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。
如果是集合类型,有两种方式:
第一种: 要求集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。 给List集合中的元素赋值,使用下标。
给Map集合中的元素赋值,使用键值对。
第二种: 接收的请求参数是json格式数据。需要借助一个注解实现。
备注:POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
基本类型:
@RequestMapping("/findAccount") public String findAccount(Integer accountId,String accountName)
{ System.out.println("查询了账户。。。。"+accountId+","+accountName);
return "success";
}
访问的URL: localhost:/findAccount?accountId=12&accountName=quan
常用注解:
1@RequestParam
作用:把请求中指定名称的参数给控制器中的形参赋值
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
public String printHello( @RequestParam(value = "age",required = false)Integer age)
2@RequestBody
作用: 用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据。 get请求方式不适用。
属性: required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值为false,get请求得到是null。
@RequestMapping("/saveAccount") public String saveAccount(@RequestBody(required = false)String body){ System.out.println(body); return "hello"; }
post:
提交之后:
结果:name=quan&money=1111
get:
http://localhost:8080/spmvc/login/saveAccount?name=quan&money
结果是null
3@PathVariable
作用: 用于绑定url中的占位符。例如:请求url中 /delete/{id},这个{id}就是url占位符。 url支持占位符是spring3.0之后加入的。
是springmvc支持rest风格URL的一个重要标志。
属性:
value:用于指定url中占位符名称。
required:是否必须提供占位符。
@RequestMapping("/pathvariable/{quan}") public String pathvariable(@PathVariable(value = "quan")String quan){ System.out.println(quan); return "hello"; } //请求:http://localhost:8080/spmvc/login/pathvariable/quanname //结果:quanname
REST风格URL详解
4@RequestHeader
作用: 用于获取请求消息头。 属性: value:提供消息头名称 required:是否必须有此消息头 注: 在实际开发中一般不怎么用。
未完成
SpringMVC响应数据的结果视图:
1字符串
返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
@Controller public class indexController { @RequestMapping("/indexxx") public String index(){ return "index"; } }
上面返回字符串,表明指定逻辑视图,之前在spring_MVC里面配置的视图解析器解析为jsp物理路径:/WEB-INF/pages/index.jsp
2void
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
这里需要引用servlet原始的API作为控制器中的方法参数
使用request转向页面
@Controller public class aboutvoid { @RequestMapping("/testReturnvoid") public void testReturnvoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("/WEB-INF/QQ.jsp").forward(request,response); } }
使用response页面重定向
@Controller public class aboutvoid { @RequestMapping("/testReturnvoid") public void testReturnvoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.sendRedirect("testab"); } }
、也可以通过response指定响应结果
response.getWriter.writer("okok")
3ModelAndView
ModelAndView是SpringMVC为我们提供的一个对象,该对象也可以用作控制器方法的返回值。
该对象有两个方法:
setView
public void setView(@Nullable View view) { this.view = view; }
addObject
public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) { this.getModelMap().addAttribute(attributeName, attributeValue); return this; }
列子:
@Controller class testModelAndView { @RequestMapping("testModelAndView") public ModelAndView testReturnModelAndView(){ ModelAndView mv = new ModelAndView(); mv.addObject("username","quan"); mv.setViewName("QQ"); return mv; } }
编写QQ.jsp
放回字符串进行转发和重定向
1forward转发
controller方法在提供了String类型的返回值之后,默认就是请求转发
@RequestMapping("testForward") public String testForward(){ System.out.println("donedone"); return "forward:/WEB-INF/jsp/index.jsp"; } //http://localhost:8080/mvc27_war/testForward
最终访问的是
如果用了formward:则路径必须写成实际视图url,不能写逻辑视图。
2Redirect重定向
@RequestMapping("testRedirect") public String testRedirect(){ System.out.println("doneall"); return "redirect:index.jsp";//如果重定向到jsp页面,则jsp页面不能写在web-inf中。 }
它相当于“response.sendRedirect(url)”。需要注意的是,如果是重定向到jsp页面,则jsp页面不能写在WEB-INF目录中,否则无法找到。
3ResponseBody响应json数据
作用: 该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
未完成
SpringMVC中的异常 处理
SpringMVC的拦截器
拦截器的作用
Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,
拦截器链中的拦截器就会按其之前定义的顺序被调用。
过滤器是servlet规范中的一部分,任何java web工程都可以使用。
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor接口。
自定义拦截器的步骤:
1编写一个普通类实现HandlerInterceptor接口
//实现拦截器,之后要进行配置 public class HandlerIntereptorD1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre1111拦截"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("post111执行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after111执行"); } }
2配置拦截器:
在springmvc的配置文件里面配置拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*"/>
<bean id="HandlerIntereceptorD1" class="com.quan.interceptor.HandlerIntereptorD1"></bean>
</mvc:interceptor>
</mvc:interceptors>
访问:http://localhost:8080/mvc27_war/indexxx
关于拦截器的细节部分
放行:
放行的含义是指,如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre1111拦截"); return true; }
当返回值是true的时候,程序才能继续执行
拦截器三个方法的说明
preHandle
如何调用: 按拦截器定义顺序调用
何时调用: 只要配置了都会调用
有什么用: 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true。
如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
postHandle
如何调用: 按拦截器定义逆序调用
何时调用: 在拦截器链内所有拦截器返成功调用
有什么用: 在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
afterHandle
如何调用:按拦截器定义逆序调用
何时调用:只有preHandle返回true才调用
有什么用:在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
拦截器的作用路径:
<mvc:mapping path="/**" /><!-- 用于指定对拦截的url -->
<mvc:exclude-mapping path=""/><!-- 用于指定排除的url-->
多个执行器的调用顺序:
例子:
第一个拦截器:
public class HandlerIntereptorD1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre1111拦截"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("post111执行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after111执行"); } }
第二个拦截器:
public class HandlerIntereptorD2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre2222拦截"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("post2222执行了"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after2222执行"); } }
配置两个拦截器:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*"/> <bean id="HandlerIntereceptorD1" class="com.quan.interceptor.HandlerIntereptorD1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/*"/> <bean id="HandlerIntereceptorD2" class="com.quan.interceptor.HandlerIntereptorD2"></bean> </mvc:interceptor> </mvc:interceptors>
结果:
中断流程测试
将上述拦截器2设置的preHandle放行即返回值设置为false
public class HandlerIntereptorD2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre2222拦截"); // 将preHandle的 返回值设置为false ,然后实现中断效果 return false; }
访问结果:
分析:
1符合拦截路径要求的,按照定义的顺序执行所有的拦截器的preHandle
2在定义逆序来执行所有拦截器的posthandle
3最后按照定义的逆序来执行所哟的after
多个拦截器的流程图:
拦截器模拟验证用户是否登陆成功
需求:
Controller:
@Controller public class LoginController { @RequestMapping(value = "login",params = {"name","age"},method = RequestMethod.DELETE ) public String login(Model model){ return "login"; } //登陆提交 @RequestMapping("/loginsubmit") public String loginsubmit(HttpSession session, String userid,String pwd){ session.setAttribute("activeUser",userid); return "redirect:/main.jsp"; } //退出 @RequestMapping("logout") public String logout(HttpSession session){ session.invalidate(); return "redirect:index.jsp"; } }
拦截器: LoginInterceptor
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if(request.getRequestURI().indexOf("login")>=0){//表示匹配URL里面的字符串login的所在位置,-1表示不存在。 return true; } HttpSession session = request.getSession(); if (session.getAttribute("activeUser") != null){ return true; } request.getRequestDispatcher("WEB-INF/jsp/login.jsp").forward(request,response); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
配置拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*"/>
<bean id="loginInterceptor" class="com.quan.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆</title>
</head>
<body>
<form action="loginsubmit" >
userid:<input type="text" name="userid"/><br>
<input type="submit" value="done">
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>main</title>
</head>
<body>
登陆done
</body>
</html>
springMVC 异常处理
原文:https://www.cnblogs.com/java-quan/p/13372280.html