1. SpringMVC调用流程
1.1 组件说明
1.1.0 Servlet作用
1.1.1 前端控制器DispatcherServlet
作用:SpringMVC中控制用户请求的转发…/响应的规则。
1.1.2 处理器映射器HandlerMapping
铺垫:404什么错误,请求资源没有找到
作用:标识用户的请求路径/后端执行的方法映射关系。
数据结构:Map<String,Method>
工作过程:当tomcat服务器启动时,带动SpringMVC的组件运行,将所有的@RequestMapping注解进行扫描,之后将请求路径当做key,注解所标注的方法当做value保存到处理器映射器中,方法用户请求之后匹配方法。
1.1.3 处理器适配器HandlerAdaptor
作用:SpringMVC中内部有很多处理器(工人),都由适配器进行统一管理(包工头),如果用户需要执行某个业务的方法,都会先由处理器适配器挑选合适的处理器去执行业务逻辑。
理解:装修的时候,先改水电找水电工,瓦工,木工…装修公司(包工头)
1.1.4 处理器Handler
说明:将来的程序从Controller层中进行执行时,是由处理器完成的。返回特定的数据,ModelAndView对象。
返回值说明:ModelAndView对象,包含两部分->Model数据(服务器返回给页面的数据)和View数据(服务器返回页面逻辑名称)。
1.1.5 视图解析器ViewReslover
作用:将用户返回的页面逻辑名称动态拼接,前缀 + 后缀,该页面就是给用户展现的页面。
例子:/WEB-INF/ajax.jsp
1.1.6 视图渲染View
说明:将返回值中的model数据,动态的填充到页面中(将数据存放到request对象中),之后在页面中通过request对象.key的方法动态获取数据,至此用户可以看到展现的页面,同时可以从request对象中动态的获取想要的数据。
1.1.7 SpringMVC调用原理
1.2 关于常见的Ajax业务说明
//2. $.ajax相关说明 最根本的ajax业务调用规则
// 函数(方法)式编程
$.ajax({
type: "get", //请求类型 $.getJSON
url: "/ajaxUser", //请求网址
data: {id:"2000",name:"tomcat猫"}, //传递的参数
dataType: "json", //定义服务器返回值类型 可以智能判断 可以省略不写
success: function(result){
//result是服务器返回的数据..
console.log(result)
},
error: function(result){
alert("服务器异常,请稍后")
},
async: true
//设定异步操作 如果涉及到ajax嵌套问题 则设置同步调用.
})
2. 京淘项目环境搭建
要求:
- 代码必须跟上。
- 项目部署阶段,问题集中式爆发(虚拟机/Linux命令)学会接受。
- 前后端调用业务流程,业务问题,听懂流程,看懂代码即可,3天…
2.1 传统架构存在问题
说明:由于单体架构设计,将所有的模块都写到了一起,如果将来某个模块发生了问题,则可能直接影响整个项目的运行。
架构设计的耦合性太高
2.2 分布式的架构设计
2.2.1 概念
说明:按照特定的规则,将项目进行拆分。
2.2.2 按照模块拆分
说明:按照特定的模块将项目拆分为独立的个体,独享一台tomcat服务器。
优点:由于服务器都是单独部署,所以某台服务器的宕机,不会影响整个项目的运行。
2.2.3 按照层级拆分
说明:由于大型的项目开发的人员较多,并且代码结构非常复杂,为了减少开发难度,将项目按照业务层级进行拆分。
2.3 关于分布式思想问题说明
2.3.1 问题说明
- 如果项目有多个,如何维护jar包文件。
- 如果项目有多个,如何统一维护工具API。
2.3.2 京淘架构设计
3.京淘后台搭建
3.1 创建父级工程
3.1.1 创建项目
3.1.2 编辑POM.xml文件
定义父级工程pom.xml文件,注意打包方式/跳过测试类打包/新jar包添加。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--项目坐标-->
<groupId>com.jt</groupId>
<artifactId>jt</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式 pom-->
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--指定maven配置属性-->
<properties>
<java.version>1.8</java.version>
<!--跳过测试类打包-->
<skipTests>true</skipTests>
</properties>
<!--添加jar包文件-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--引入MybatisPlus配置 删除原有Mybatisjar包 不然造成冲突 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--springBoot整合JSP添加依赖 -->
<!--servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--jstl依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!--使jsp页面生效 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--添加httpClient jar包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--引入dubbo配置 -->
<!--<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>-->
<!--添加Quartz的支持 -->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>-->
<!-- 引入aop支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--spring整合redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
</dependencies>
</project>
3.2 创建common项目
3.2.1 创建common项目
3.2.2 jt_common导入src属性
说明:将课前资料中的jt-common的src文件导入。
3.3 创建jt_manage
3.3.1 创建项目
3.3.2 添加继承/依赖/插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jt_manage</artifactId>
<!--打包方式-->
<packaging>war</packaging>
<!--1.定义父级-->
<parent>
<artifactId>jt</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--2.添加依赖-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--3.配置build标签 业务系统必须添加build标签-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.3.3 导入静态资源文件
说明:将课前资料中的文件jt-manage的src文件导入。
3.3.4 修改YML配置
修改数据源配置信息
3.3.5 修改启动项配置
3.4 关于默认页面跳转说明
问题说明:当用户通过http://localhost:8091/会默认的跳转一个页面,页面名称index.html/index.jsp
说明:当什么都没有写的时候,会动态的配置默认的规则,发起index请求,根据index请求,动态拼接视图解析器的前缀和后缀**/WEB-INF/views/index.jsp**
3.5 关于页面结构分析
3.5.1 页面布局
<body class="easyui-layout">
<div data-options="region:'west',title:'菜单',split:true" style="width:10%;"></div>
<div data-options="region:'center',title:'首页'"></div>
</body>
3.5.2 树形结构
<ul class="easyui-tree">
<li>
<span>商品新增</span>
<ul>
<li>新增</li>
<li>修改</li>
</ul>
</li>
</ul>
3.5.3 选项卡技术
页面标签
<li><a οnclick="addTab('商品新增','/item-add')">商品新增</a></li>
页面JS:
var url2="https://map.baidu.com/search/%E5%8C%97%E4%BA%AC%E7%9F%B3%E6%99%AF%E5%B1%B1%E6%B8%B8%E4%B9%90%E5%9B%AD/@12936575.10359031,4826331.968205,16.56z?querytype=s&da_src=shareurl&wd=%E5%8C%97%E4%BA%AC%E7%9F%B3%E6%99%AF%E5%B1%B1%E6%B8%B8%E4%B9%90%E5%9B%AD&c=131&src=0&pn=0&sug=0&l=16&b=(12934842.424322959,4825537.372322239;12938307.78285766,4827126.564087762)&from=webmap&biz_forward=%7B%22scaler%22:1,%22styles%22:%22pl%22%7D&device_ratio=1"
//画中画效果
var content = '<iframe scrolling="auto" frameborder="0" src="'+url2+'" style="width:100%;height:100%;"></iframe>';
//title: 选项卡标题
//content : 选项卡中展现的页面信息
//closable: 选项卡是否可以关闭.
$('#tt').tabs('add',{
title:title,
content:content,
closable:true
});
3.6 通用页面跳转
3.6.1 业务需求说明
根据规范:请求应该访问后端服务器,之后跳转到指定的页面中。
如果每次都是通过后端方法实现页面的跳转,很繁琐,能否优化?
<li data-options="attributes:{'url':'/page/item-add'}">新增商品</li>
<li data-options="attributes:{'url':'/page/item-list'}">查询商品</li>
<li data-options="attributes:{'url':'/page/item-param-list'}">规格参数</li>
3.6.2 编辑IndexController
package com.jt.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
/**
* /page/item-add' item-add.jsp
* /page/item-list item-list.jsp
* /page/item-param-list' item-param-list.jsp
* 需求: 能否利用一个方法实现通用的页面处理.
* 方法: restFul风格(一)
* 语法:
* 1.利用/方式进行参数分割
* 2.利用{}括号的形式动态接受参数
* 3.利用@PathVariable 动态接受参数
*
* 方法: restFul风格(二)
* 利用不同的请求类型,实现不同的业务功能
* 查询业务 GET
* 更新业务 PUT
* 删除业务 DELETE
* 新增业务 POST
*/
@RequestMapping("/page/{modelName}")
public String itemAdd(@PathVariable String modelName){
return modelName;
}
}
4.商品列表展现
4.1关于子类与父类私有属性的说明
子类继承父类,只能继承父类的共有的方法。
说明:由于继承了父类的方法,JVM解析数据时,发现如果该子类中没有特定的属性,则动态的在编译期生成该属性及方法。
4.2 表结构
编辑ItemPOJO对象
@JsonIgnoreProperties(ignoreUnknown=true) //表示JSON转化时忽略未知属性
@TableName("tb_item")
@Data
@Accessors(chain=true)
public class Item extends BasePojo{ //子类继承父类 也实现了序列号接口
@TableId(type=IdType.AUTO)
private Long id; //商品id
private String title; //商品标题
private String sellPoint; //商品卖点信息
private Long price; //商品价格 Long > dubbo
private Integer num; //商品数量
private String barcode; //条形码
private String image; //商品图片信息 1.jpg,2.jpg,3.jpg
private Long cid; //表示商品的分类id
private Integer status; //1正常,2下架
//为了满足页面调用需求,添加get方法
public String[] getImages(){
return image.split(",");
}
}
4.3 关于JSON结构说明
4.3.1 什么是JSON
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。
4.3.2 JSON格式
- 对象格式
- 数组格式
- 嵌套格式
案例:
{"id":"100",
"name":"tomcat猫",
"hobbys": ["敲代码","打游戏"],
"food":[{"name":"番茄炒蛋","price":"15"},{"name":"黄焖鸡米饭","price":"30"}]
}
4.3 关于表格数据展现说明
4.3.1 表格数据JSON结构
{
"total":2000,
"rows":[
{"code":"A","name":"果汁","price":"20"},
{"code":"B","name":"汉堡","price":"30"},
{"code":"C","name":"鸡柳","price":"40"},
{"code":"D","name":"可乐","price":"50"},
{"code":"E","name":"薯条","price":"10"},
{"code":"F","name":"麦旋风","price":"20"},
{"code":"G","name":"套餐","price":"100"}
]
}
4.3.2 封装VO对象 EasyUITable
说明:在jt-manage中定义vo包,代码格式如下:
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class EasyUITable {
private Long total; //定义记录总数
private List<Item> rows; //定义记录
}
4.3.3 编辑表格页面
如果表格页面中添加了分页的组件,则请求时会自动的携带分页的参数 page=当前页,rows=展现条数。
<table class="easyui-datagrid" id="itemList" title="商品列表"
data-options="singleSelect:false,fitColumns:true,collapsible:true,pagination:true,url:'/item/query',method:'get',pageSize:20,toolbar:toolbar">
<thead>
<tr>
<th data-options="field:'ck',checkbox:true"></th>
<th data-options="field:'id',width:60">商品ID</th>
<th data-options="field:'title',width:200">商品标题</th>
<th data-options="field:'cid',width:100,align:'center',formatter:KindEditorUtil.findItemCatName">叶子类目</th>
<th data-options="field:'sellPoint',width:100">卖点</th>
<th data-options="field:'price',width:70,align:'right',formatter:KindEditorUtil.formatPrice">价格</th>
<th data-options="field:'num',width:70,align:'right'">库存数量</th>
<th data-options="field:'barcode',width:100">条形码</th>
<th data-options="field:'status',width:60,align:'center',formatter:KindEditorUtil.formatItemStatus">状态</th>
<th data-options="field:'created',width:130,align:'center',formatter:KindEditorUtil.formatDateTime">创建日期</th>
<th data-options="field:'updated',width:130,align:'center',formatter:KindEditorUtil.formatDateTime">更新日期</th>
</tr>
</thead>
请求路径:
4.3.4 编辑ItemController
package com.jt.controller;
import com.jt.pojo.Item;
import com.jt.vo.EasyUITable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.jt.service.ItemService;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/item")
public class ItemController {
@Autowired
private ItemService itemService;
/**
* 业务说明: 根据分页实现商品查询
* URL地址: http://localhost:8091/item/query?page=1&rows=20
* 参数: page/rows
* 返回值: EasyUITable
*/
@RequestMapping("/query")
public EasyUITable findItemByPage(Integer page, Integer rows){
return itemService.findItemByPage(page,rows);
}
}
4.3.5 编辑ItemService
package com.jt.service;
import com.jt.pojo.Item;
import com.jt.vo.EasyUITable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jt.mapper.ItemMapper;
import java.util.List;
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override
public EasyUITable findItemByPage(Integer page, Integer rows) {
//1.获取记录总数
long total = itemMapper.selectCount(null);
//2.分页查询
//sql: select * from tb_item limit 起始位置,查询记录数
//第一页: select * from tb_item limit 0,20 0-19
//第二页: select * from tb_item limit 20,20 20-39
//第三页: select * from tb_item limit 40,20 40-59
int startIndex = (page-1) * rows;
List<Item> pageList = itemMapper.findItemByPage(startIndex,rows);
return new EasyUITable(total,pageList);
//3.尝试使用MP的分页 进行查询
}
}
4.3.6 编辑ItemMapper
package com.jt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.Item;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface ItemMapper extends BaseMapper<Item>{
/*要求 越火爆的商品 排序靠前 以更新时间倒叙排列*/
@Select("select * from tb_item order by updated desc limit #{startIndex},#{rows}")
List<Item> findItemByPage(int startIndex, Integer rows);
}