企业级应用中的软件的分层的基本架构(参考阿里巴巴开发手册)
说明:分层架构的本质是分而治之,已达到分解问题复杂性的目的,从而更好的进行设计与实现。
基于servlet,jsp,javabean技术实现的MVC架构,具体架构图如下:
Spring MVC是MVC架构模式的一种完美实现,它简化了Java WEB 中基于MVC架构的编程过程,是Spring中的WEB应用模块。
Spring MVC 底层核心架构图及工作流程(先了解,写完项目案例再重点强化)
Spring MVC 中的五大核心组件:
1) DispatcherServlet (前端控制器, 处理请求的入口)
2) HandlerMapping (映射器对象, 用于管理url与对应controller的映射关系)
3) Interceptors(拦截器,实现请求响应的共性处理)
4) Controller (后端控制器, 负责处理请求的控制逻辑)
5) ViewResolver(视图解析器,解析对应的视图关系:前缀+view+后缀)
备注:假如希望了解Spring MVC的详细处理流程可以基于断点调试法进行跟踪。
Step01:创建maven web 项目并解决项目中的错误问题
Step02:添加Spring MVC项目核心依赖
Step03:配置Spring MVC项目核心组件
Step04:创建Spring MVC 后端控制器及页面
Step05:部署及测试spring mvc 项目应用。
2.2. Spring MVC 编程基础实现(重点)
2.2.1. 创建Maven WEB 项目并添加Spring MVC 依赖
Step01:创建maven web项目
1) 项目名 CGB-SPRING-MVC-01
2) Web项目打包方式为war方式
Step02:配置maven web项目
1) 生成web.xml(项目视图)
2) Web项目的target runtimes为tomcat
3)Web 项目的编译版本为JDK1.8
Step03: 添加Spring MVC项目依赖
org.springframework
spring-webmvc
4.3.9.RELEASE
2.2.2. 添加Spring MVC配置文件并进行基本配置
在项目的resources的目录中添加核心配置文件(例如spring-configs.xml)并进行基本配置
说明:配置文件的名字可以自己指定。
2.2.3. 配置Spring MVC前端控制器
打开web.xml,配置DispatcherServlet对象
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-configs.xml
1
dispatcherServlet
*.do
前端控制器是spring mvc处理请求的入口,是springmvc的核心,这个控制器一般需要在服务器启动时即初始化。
其中
1) load-on-startup 表示启动时则加载此servlet,数字越小优先级越高.
2) init-param 中的参数名不能变(此名字在DispatcherServlet父类中定义)
2.2.4. 创建并配置Spring MVC后端控制器
编写Spring MVC后端控制器
@Controller
@RequestMapping("/")
public class HelloController{
@RequestMapping("doSayHello")
public ModelAndView doSayHello() {
ModelAndView mv=new ModelAndView("hello");
mv.addObject("message", "helloworld");
return mv;
}
}
其中:
1)通过@RequestMapping注解定义url到controller具体方法的映射,这个映射信息会被存储,一般是存储到一个HandlerMapping对象中.
2)ModelAndView对象为一个模型与视图对象,内置一个map对象,主要用于封装业务数据和视图名。
3)ModelAndView构造方法中传递的为视图名,addObject方法可以以key/value形式存储数据。
4)ModelAndView 对象返回时会被spring mvc自动存储到请求作用域,在对应的视图页面可以直接从此作用域获取对应的值。
2.2.5. 创建JSP页面对象
在项目的WEB-INF/pages文件夹下创建hello.jsp文件,然后设置其内容,例如
…
${message}
…
说明:WEB-INF目录下的资源不能允许通过浏览器地址栏直接访问。
2.2.6. 部署并运行项目以及请求响应流程分析
将项目部署到tomcat,然后启动运行,在地址栏输入具体url访问对应controller对象。
问题分析:
1) tomcat启动时出现ClassNotFoundException,而这个class又不是我们自己的类,此时要重新maven update,重新发布(右键tomcat 重新publish),多次尝试还是不可以,此时重启eclipse。
2) 404异常,一般表示服务端资源没找到,首先检测访问路径是否正确,然后还可以在项目的部署目录中去查找对应的资源,必须确保资源是存在的,假如资源不存在,说明代码没有正常编译。(很常见)
3) 如何解决这种项目不编译的问题?四大Clean
step01) 停止tomcat将tomcat下的项目移除,并clean你的tomcat服务器(两个clean)
step03) 对项目进行maven clean操作(清除原先编译结构,然后重新编译)
step04) 再次对项目进行clean操作(菜单栏中的project clean)
step05) 重新部署项目,启动tomcat运行
step06) 假如经历了以上几个步骤,还没解决此问题,重启eclipse再试
说明:假如你的eclipse经常出现类似问题,换jdk。
4) 运行项目时尽量不要右键运行选在run as /run on server
Tomcat 启动及对象加载流程分析:
项目的请求处理流程结构及过程解析:
Step01:客户端向服务服务端发请求
Step02:服务端对请求信息进行过滤(Filter)
Step03:请求到达前端控制DispatcherServlet
Step04:前端控制器基于url在HandlerMapping中的映射找请求执行链
Step05:执行执行链中的拦截器(Interceptor)方法
Step06:执行执行链中的控制器(Controller)方法
Step07:对象控制层返回的视图进行解析
Step08:向客户端返回一个响应结果。
实际项目中我们要借助@RequestMapping注解定义映射路径。其注解应用位置
ü 类定义处: 提供初步的请求映射信息。
ü 方法定义处: 提供进一步的细分映射信息
3.1.1. 普通url映射
@RequestMapping(value={"/doSayHello", "/user/doSayWelcome"}):
多个URL路径可以映射到同一个处理器的功能处理方法。
3.1.2. Rest风格url映射
REST即表述性状态传递(英文:Representational State Transfer,简称REST),是一种软件架构编码风格,是基于网络应用进行设计和开发的编码方式。可以降低开发的复杂度,提高程序的可伸缩性。例如:
@RequestMapping("/msg/{xxx}")
请求的URL可以是“/msg/hello”或“/msg/welcome”
@RequestMapping("/msg/{id}/create"):
请求的URL可以是“/users/1/create”。
@RequestMapping("/msg/{mId}/topics/{tId}")
这样也是可以的,请求的URL可以是“/users/10/topics/12”。
说明:通过@PathVariable可以提取URI模板模式中的{×××}中的×××变量。
http://localhost:8080/项目名/doUpdate/1.do
项目中Controller层对象的每个方法默认可以处理任意方式的请求,假如要指定控制层方法只能处理GET或只能处理POST请求,那该如何实现呢?
借助@RequestMapping注解中的method属性指定具体的请求处理方式,例如
@RequestMapping(value=”doSaveObj”,
method=RequestMethod.POST)
public String doSaveObject(Object obj){….}
知识点扩展:
1)@GetMapping 注解应用(定义的映射只能处理get请求)
2)@PostMapping 注解应用(定义的映射只能处理post请求)
3.2.2. 请求方式组合
项目中还可在控制层方法上借助@RequestMapping注解中的method属性指定使用哪几种方式处理请求。
@RequestMapping(value=”doSaveObj”,
method={RequestMethod.POST,
RequestMethod.GET})
public String doSaveObject(Object obj){….}
提示:一般浏览器只支持GET或POST方式。
请求映射方法中可以直接使用ServletAPI 中的对象获取参数数据,例如HttpServletRequest,HttpSession对象等,例如:
@RequestMapping(value="withRequest",method=RequestMethod.GET)
@ResponseBody
public String withRequest(HttpServletRequest request){
System.out.println(request.getRequestURI());
return "Obtainer 'foo' query parameter value'"+request.getParameter("gid")+"'";
}
提示:@ResponseBody注解作用:该注解作用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区,使用情况:返回的数据不是Html标签的页面,而是其他数据格式的数据时,(如Json、xml,普通文本等)使用;
3.3.2. 直接量对象(重点)
SpringMVC 请求一个控制层资源时,可以在对应方法中直接使用参数变量接收参数数据,但参数变量的类型建议为对象类型。
1)使用String类型变量接受请求参数的值:
@RequestMapping(value="withStringParam",method=RequestMethod.GET)
@ResponseBody
public String withStringParam(@RequestParam String foo) {
return "Obtained 'foo' query parameter value '" + foo + "'";
}
提示:@RequestParam注解用于接收请求参数中名字为foo的参数值,假如请求参数名与方法中的参数名一致,@RequestParam注解可以省略。假如不一致则可以使用@RequestParam注解定义新的参数名直接接收页面数据,然后传递给方法名,还有就是请求参数中包含特殊字符时,需要借助@RequestParam注解对参数进行声明。例如
@RequestMapping(value="withStringParam", method=RequestMethod.GET)
@ResponseBody
public String withStringParam(@RequestParam(value="param-01",required=false) String foo) {
return "Obtained 'foo' query parameter value '" + foo + "'";
}
提示:required=false表示,参数可以不存在,假如为true(默认),参数不存在时会抛出异常(400异常)。
2)使用Date类型变量接受请求日期参数的值:
@RequestMapping(value="withDateParam")
@ResponseBody
public String withDateParam(Date birthday) {
return "Obtained date parameter value '" + birthday + "'";
}
Spring MVC 默认支持yyyy/MM/dd格式日期转换,假如日期格式不匹配会报400异常
3)使用Integer类型的可变参数或数组接收请求数据
@RequestMapping(value="withVarParam")
@ResponseBody
public String withVarParam(Integer… ids) {
return "Obtained ids parameter value '" + ids + "'";
}
3.3.3. Java bean对象(重点)
当请求中多个参数时可以通过在方法中定义多个参数接收参数数据,也可以利用一个javabean对象接收多个参数数据以简化多个参数变量的定义。
@RequestMapping(value="withParamGroup",method=RequestMethod.GET)
@ResponseBody
public String withParamGroup(SysLog entity) {
return "Obtained javabean parameter group " + entity;
}
提示:当使用javabean接收请求参数数据时,bean中需要有与参数名对应的set方法。
3.3.4. 集合Map对象对象(了解)
说明: 通过map接收页面参数时,需要使用@RequestParam注解声明
@RequestMapping("doMap02")
public String withParamGroup (@RequestParam Map map) {
return "Obtained map parameter group " + map;
}
提示:此时的map不能再作为响应数据的封装对象
3.3.5. Rest url数据(重点)
SpringMVC请求资源路径的URL可以通过{XXX}形式指定动态的URL,动态URL中的这个可变参数的值可以直接注入到方法对应的参数中。
@RequestMapping(value="path/{var}",method=RequestMethod.GET)
@ResponseBody
public String withPathVariable(@PathVariable String var) {
return "Obtained 'var' path variable value '" + var + "'";
}
通过@PathVariable注解指定参数变量var获取请求url中{var}数据
3.3.6. 请求头数据(了解)
1)当服务端要获取客户端请求头中数据信息时,可通过@RequestHeader即可将请求头中的属性值绑定到处理方法的入参中,例如获取请求中Accept属性的值,然后传入到对应方法的参数中。
@RequestMapping(value="header", method=RequestMethod.GET)
@ResponseBody
public String withHeader(@RequestHeader String Accept) {
return "Obtained 'Accept' header '" + Accept + "'";
}
2)假如希望在此方法中直接从cookie取值,可以定义参数时使用@CookieValue对参数进行修饰,参数名一般要与cookie对象中的key相同
@RequestMapping(value="withCookie")
@ResponseBody
public String withCooke(@CookieValue String JSESSIONID) {
return "Obtained COOKIE Value '" + JSESSIONID + "'";
}
提示:方法中的参数名需要与请求头参数中某个参数名相同,具体请求头相关信息可以在浏览器控制台查看。
3)当应用中要获取请求中所有数据时可以在请求方法中定义一个HttpEntity
@RequestMapping(value="entity", method=RequestMethod.POST)
public @ResponseBody String withEntity(HttpEntity entity) {
return "Posted request body " + entity.getBody() + "headers = " + entity.getHeaders();
}
如上写法:了解
4.1. 响应数据封装
4.1.1. Servlet API 对象(了解)
将请求数据直接封装到Request 对象
@RequestMapping("doResponse01")
public String doResponse01(HttpServletRequest request) {
request.setAttribute("data", "hello..");
return "response";
}
在response.jsp页面可以直接借助${data}方式获取数据。
当方法中直接返回一个页面时,默认执行的是请求转发,假如需要实现重定向,
可以在返回的地址后添加redirect,例如 return "redirect:responseUI.do"; 其中responseUI.do对应一个请求url.
@RequestMapping("doResponse02")
public String doResponse02(HttpServletRequest request) {
request.setAttribute("data", "hello..");
return "redirect:responseUI.do";
}
在如上方法中可以重定向到一个responseUI对应的新的URL。
@RequestMapping("responseUI")
public String responseUI() {
return "response";
}
在新的请求中不能直接获取上一个请求作用域的数据。
回顾请求转发与重定向:
1)请求转发(forward)
2) 重定向(redirect)
4.1.2. ModelAndView 对象(重点)
在对服务端响应数据进行封装时,可以直接在方法参数中定义一个ModelAndView类型的参数,借助ModelAndView对象封装响应数据.
@RequestMapping("doModelAndView")
public ModelAndView doModelAndView(ModelAndView mv) {
//ModelAndView mv=new ModelAndView();
mv.addObject("data", "model and view");
mv.setViewName("response");//view
return mv;
}
提示:ModelAndView 对象由Spring创建,并可以将数据存储到ModelAndView对象的ModalMap类型的属性中(可参考源代码).
4.1.3. Model对象(重点)
将响应数据直接封装为model中。
@RequestMapping("doModel")
public String doModel(Model model) {
model.addAttribute("data", "modal");
return "response";
}
当我们返回具体view时,系统底层会自动将model对象存储到request作用域。
4.1.4. Map对象(了解)
将响应数据封装到Map中(我建议假如使用map对数据进行封装,可直接采用model对象)。
@RequestMapping("doMap01")
public String doMap01(Map map) {
map.put("data", "map..");
return "response";
}
4.2.1. JSON 应用概述
JSON(JavaScript Object Notation):一种轻量级数据交换格式,通常作为客户端与服务端进行数据交互的一种标准。
企业级Java项目数据传输方式:
reponse.getWriter().write(jsonStr);
客户端访问服务端时,服务器从数据库取出数据进行封装,然后再将对象转换为json串,通过网络传输到客户端。
4.2.2. Spring 集成jackson库
spring 中默认支持jackson应用的,但使用时需要添加jackson依赖,例如
com.fasterxml.jackson.core
jackson-databind
2.8.5
创建Controller中例如ResponseController,然后在类中添加对应方法。例如:
将Map对象内容转换为字符串(spring底层会直接访问jackson api将对象转换为字符串)
@RequestMapping("doMap")
@ResponseBody
public Map doMap(){
Map map=new HashMap<>();
map.put("id", 100);
map.put("name", "AAA");
return map;
}
将JavaBean对象转换为JSON串
@RequestMapping("doUser")
@ResponseBody
public SysLog doLog(){
SysLog log=new SysLog ();
log.setId(100);
log.setUsername("CCC");
log.setIP("192.168.1.12");
return log;
}
将Java List集合转换为JSON串。
@RequestMapping("doList")
@ResponseBody
public List doList(){
List list=new ArrayList<>();
SysLog log=new SysLog ();
log.setId(100);
log.setUsername("CCC");
log.setIP("192.168.1.12");
list.add(log);
log=new SysLog ();
log.setId(100);
log.setUsername("CCC");
log.setIP("192.168.1.12");
list.add(log);
return list;
}
备注:将来controller中数据来自服务端数据。