电商网购系统
准备工作
创建聚合工程
父级工程 打pom包
只做jar包依赖管理,本工程中所有项目都作为它的子工程,全部都需要继承它
pom.xml文件中添加整个项目的依赖
web依赖, mysql数据库驱动,jdbc,mybatis-plus,servlet,jsp,jstl,httpclient,dubbo,aop,jedis,Quartz,lombok,devtools热部署,test
//build标签只有添加了主启动类的java文件才需要 父级工程只做jar包的定义
通用common项目
做共性提取,作为jar包被其他项目依赖引入
pojo包下:
BasePojo(创建时间及修改时间的定义)
Item(商品pojo类) 使用mybatis-plus注意pojo类和数据库表的关联
添加Dubbo接口
管理manager项目
war包
pom文件中:继承依赖,插件
yml配置文件:
server端口,根路径
spring数据源,mvc的前后缀
mybatis-plus的mapper映射文件路径,开启驼峰命名
logging日志debug配置
dubbo包扫描,应用名称,注册中心,指定协议名称及端口号
注意:有静态资源展现的貌似都需要配置启动项(工作目录设为项目路径及右上角存储为项目文件打勾)
通用跳转页面
/*
restFul风格实现1:
1.参数与参数之间使用/分隔
2.参数使用{}形式包裹
3.@PathVariable 实现数据的转化.
restFul风格实现2:可以利用请求的类型,指定业务功能.
TYPE="GET" 查询业务
TYPE="POST" 新增业务
TYPE="PUT" 更新业务
TYPE="DELETE" 删除业务 */
@GetMapping("/page/{moduleName}")
public String itemAdd(@PathVariable String moduleName){
return moduleName;
}
前端使用EasyUI
商品列表展现
定义vo对象(前端需要什么就封装为什么)
package com.jt.vo;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
// 当服务之间字节数组(对象)传递时,必须实现序列化接口.
// json的本质就是字符串可以直接传递.
public class EasyUITable implements Serializable{
private Integer total;
private List<Item> rows;
}
controller层
接收请求传参(页码值,显示行数)
调用service执行查询商品的方法
返回service层查询出的封装记录数及商品信息的list集合的vo对象即可
service层
接收controller传参(页码值,显示行数)
计算出起始位置(页码值-1)*显示行数
根据传参(起始位置,显示行数)调用dao执行分页查询业务方法在dao文件方法上注解@Select(“sql”)执行分页查询
调用dao直接使用plus的API方法selectCount(null)即可查询出总记录数 --(单表查询mybatis-plus)
返回封装记录数及商品信息的list集合的vo对象即可
dao层Mapper接口(继承BaseMapper)
定义分页查询的方法注解执行sql即可
总记录数通过plus的API执行,不需要定义方法
service中也可以通过mybatis-plus机制分页 需要编辑分页配置类配合使用
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override
public EasyUITable findItemByPage(Integer page, Integer rows) {
//查询条件根据更新时间进行排序.
QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("updated");
//当用户将参数传递之后,MP会自己执行分页操作后,将需要的数据进行封装.
//定义分页对象 (当前页码值,显示行数)
IPage<Item> iPage = new Page<>(page,rows);
//根据分页对象执行数据库查询,之后获取其其他分页数据.
iPage = itemMapper.selectPage(iPage,queryWrapper);
//获取总记录数
int total = (int)iPage.getTotal();
//获取分页后的结果
List<Item> itemList = iPage.getRecords();
//封装返回值 返回
return new EasyUITable(total,itemList);
}
}
分页配置类
package com.jt.config;
//1.标识配置类 配置类一般与@Bean注解联用!!!
@Configuration
public class MybatisPlusConfig {
//需要将对象交给容器管理Map集合 map<paginationInterceptor方法名,实例化之后的对象>
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
商品分类信息回显
pojo类封装商品分类的对象
@TableName(“tb_item_cat”) @Data @Accessors(chain = true)
@TableId(type = IdType.AUTO)
属性:
商品分类id,商品分类父级id,分类名称,商品状态信息,排序号,是否为父级
controller层
添加@CacheFind(key=“ITEM_CAT_NAME”)缓存注解,执行该方法前会先去查缓存,缓存有数据直接返回数据
接收请求获取参数(商品分类id)
调用service层查询分类名称并返回结果即可
service层
根据controller层传参商品分类id调用dao层执行查询获取商品分类对象后getName()获取名字并返回
注意:若有ajax嵌套时,内层的ajax设置为同步模式.可以正确的展现数据async:false即可
商品分类树形结构展现 --实现商品分类的缓存
一般电商网址的商品分类信息一般都是3级菜单,级与级之间存在父子级关系,一般涉及到父子级关系时,采用parentId的形式进行关联.
/*查询一级商品分类信息 父级Id=0*/
select * from tb_item_cat where parent_id=0;
/*查询二级商品分类信息 父级一级ID*/
SELECT * FROM tb_item_cat WHERE parent_id=1;
/*查询三级商品分类信息 父级二级ID*/
SELECT * FROM tb_item_cat WHERE parent_id=2;
vo对象封装EasyUItree的 --展现树形结构的数据
属性:
商品分类id,商品分类名称text(属性名字是框架定义好的,不能修改),状态信息(是否为父级,父级则关闭losed,否则为子级open)
controller层 --异步树控件加载(当展现了树形结构之后,当展开树形节点时会向后台传递该节点的id值)
接收请求,获取参数(分类节点的id),判断id并赋值
@RequestMapping("/list")
public List<EasyUITree> findItemCatList(Long id){
//当初始时树形结构没有加载不会传递ID,所以ID为null.只需要传递0.
Long parentId = (id==null)?0:id;
return itemCatService.findItemCatList(parentId);
调用service层执行查询缓存中是否有分类信息的方法传参(parentId),并返回即可
service层 –已经启动redisCluster缓存服务器并定义了redis的配置类(@Configuration @propertySource @Value @Bean JedisCluster )
加入redis缓存 若有缓存数据则直接查询缓存,若缓存没有再去查询数据库
1 定义EasyUITree的list空集合
2 定义插入缓存的key值 “ITEM_CAT_PARENTID::”+parentId; --动态拼接
3 从缓存中查询数据 jedis.get(key);
4 若为空则调用dao查询数据库查出EasyUITree对象转化为treeList对象后通过ObjectMapper转化为Json对象将key和json存入redis中
5 否则redis中获取到缓存数据json通过ObjectMapper对象转化为treeList对象即可
6 返回treeList对象即可
将ItemCat信息转化为EasyUITree对象
//将数据进行转化. cartList遍历 封装EasyUITree 添加到集合中即可
List<EasyUITree> treeList = new ArrayList<>();
for (ItemCat itemCat: catList){
Long id = itemCat.getId();
String text = itemCat.getName();
//是父级就打开 否则关闭
String state = itemCat.getIsParent()?"closed":"open";
EasyUITree easyUITree = new EasyUITree(id, text, state);
//3.封装返回值数据
treeList.add(easyUITree);
}
return treeList;
返回的是List
使用AOP编程将redis缓存加入到Aspect切面中后期需要缓存的方法直接添加注解即可实现缓存业务
定义redis配置类
(@Configuration @propertySource @Value @Bean JedisCluster )
定义Aspect切面类 --AOP编程 注解自己定义cacheFind
DI依赖注入JedisCluster缓存对象
@Around通知方法中(ProceedingJoinPoint joinPoint , CacheFind cacheFind)
1 通过缓存注解对象获取redis缓存中的key(没有动态拼接时的前缀) cacheFind.key();
2 通过joinPoint对象获取目标对象的参数array数组
3 key += “::” +Arrays.toString(array);动态拼接为真正的缓存中的key值
4 判断缓存中是否有key值对应的数据,有则取出得到json串对象
5 通过方法签名对象获取目标方法返回值类型
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class targetClass = methodSignature.getReturnType();
6 通过ObjectMapper对象read方法(json,对象类型)转化为对象实体类型result结果对象
7 若缓存中没有key则执行目标方法查询数据库返回result结果对象(封装数据的对象实体类)
8 将对象实体转化为json后将key和json存入缓存中
9 返回result结果对象即可
商品后台维护
新增商品
SysResult对象
属性:
状态码,状态信息,服务器返回的封装业务数据对象
并且定义常用的方法static修饰方便调用(成功,失败的,数据对象为参数成功的)
controller层
接收请求及商品对象实体类
调用service层保存商品返回成功SysResult即可
service层
接收controller层传来的商品对象,并为该商品对象设置上架状态信息,创建时间,更新时间
调用dao层执行insert方法插入数据库即可
定义全局异常处理类 --通过AOP实现
package com.jt.aop;
@RestControllerAdvice //作用: 标识我是一个通知方法,并且只拦截Controll层的异常.并且返回JSON.
public class SysResultException {
//ExceptionHandler 配置异常的类型,当遇到了某种异常时在执行该方法.
@ExceptionHandler(RuntimeException.class)
public Object exception(Exception e){
e.printStackTrace(); //日志记录/控制台输出. 让程序员知道哪里报错!!!
return SysResult.fail();
}
}
编辑修改商品中的商品分类名称回显
ajax请求发送分类id,controller接收请求及参数(分类id),调用service层查询出name并返回即可
商品修改
controller层
接收请求及参数(商品实体对象)
调用service根据商品实体对象为参数,执行更新商品信息方法即可
service层
为商品实体对象设置更新时间(new Date())
调用dao根据id更新商品信息即可
时间数据填充优化
基础pojo类上添加注解 BasePojo类
@Data
@Accessors(chain=true)
public class BasePojo implements Serializable{
@TableField(fill = FieldFill.INSERT) //新增有效
private Date created;
@TableField(fill = FieldFill.INSERT_UPDATE) //新增和更新有效
private Date updated;
}
编辑配置类完成自动赋值操作
package com.jt.auto;
@Component //将该对象交给spring容器管理
public class MyMetaObjectHandler implements MetaObjectHandler {
/**在POJO中添加了 新增/更新的注解,但是必须在数据库的字段中完成赋值的操作.所以.必须明确,新增/更新时操作的是哪个字段,及值是多少*/
@Override
public void insertFill(MetaObject metaObject) {
this.setInsertFieldValByName("created", new Date(), metaObject);
this.setInsertFieldValByName("updated", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setUpdateFieldValByName("updated", new Date(), metaObject);
}
}
商品删除
controller层
接收请求及参数(选中的要删除的商品的ids)
调用service层执行删除操作
返回JsonResult响应结果
service层
根据传来ids调用dao执行删除操作的方法
dao层mapper接口
定义根据ids删除的方法
mapper文件
定义删除的sql语句 foreach标签
<mapper namespace="com.jt.mapper.ItemMapper">
<!--删除Item数据信息
单值: 数组 collection="array"
单值: list集合 collection="list"
多值: 利用@Param注解封装 collection="key".
-->
<delete id="deleteItems">
delete from tb_item where id in (
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)
</delete>
</mapper>
商品上下架
controller层
接收请求及参数(状态信息 , 选中要求改状态的商品的ids)
调用service层传参(状态信息 , 选中要求改状态的商品的ids)执行修改状态的方法
返回JsonResult成功的结果即可
service层
创建空的商品对象,将状态信息设置进去
定义更新的条件构造器
将数组ids转化为list集合Arrays.asList(ids);
将ids的集合传入更新操作的条件构造器中
调用dao执行更新操作(item,updateWapper) –item只是存了传来的上下架状态信息的空对象会根据对象中有的值执行更新操作,貌似没有的值不会动它
富文本编辑器
商品信息及商品详情入库操作
KindEditor是一套开源的HTML可视化编辑器,所见即所得编辑效果,图片,文本内容都能获取及存储
js中引入KindEditor即可
编辑pojo类 --存储商品详情的(包含文本内容及图片等)
对应数据库@TableName(“tb_item_desc”)
@Data @Accessors(chain=true)
属性:
itemId对应的是商品表的id一致的
itemDesc 商品详情
mapper接口
继承BaseMapper
crud操作时商品信息与商品详情一起入库
controller层
接收请求及参数(商品实体类,商品详情实体类)
调用service层执行保存方法
返回JsonResult的成功信息即可
service层
开启事务
接收controller层(商品实体类,商品详情实体类)
为商品实体对象添加上架状态1
调用商品dao执行插入商品操作
通过商品实体获取商品id,并将id存入商品详情实体中
调用商品详情dao执行插入操作
商品详情数据回显
controller层
接收请求及传来参数商品id
调用service层根据商品id获取商品详情数据
返回JsonResult(详情对象)即可
service层
根据商品id调用dao层查询商品信息出对象
商品的修改,删除操作
…
文件上传(图片等多媒体文件)
jsp页面中form表单标签上开启多媒体属性enctype="multipart/form-data"即可在需要的位置插入多媒体文件即可
封装VO对象 --封装多媒体文件的对象
{“error”:0,“url”:“图片的保存路径”,“width”:图片的宽度,“height”:图片的高度}
说明:
error: 代表文件上传的错误. 0 文件上传正确 1.文件上传失败.
url地址: 访问图片的网络地址… 用户通过url地址获取图片信息
访问图片的物理地址… 真实存储的地址 D:/a/a.jpg
package com.jt.vo;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO implements Serializable {
//{"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
private Integer error;
private String url; //图片虚拟访问路径
private Integer width; //宽度
private Integer height; //高度
//success fail
public static ImageVO fail(){
return new ImageVO(1,null,null,null);
}
public static ImageVO success(String url,Integer width,Integer height){
return new ImageVO(0, url, width, height);
}
}
image.properties配置文件
image.dirPath=D:/JT-SOFT/images
image.urlPath=http://image.jt.com
controller层 --先保存到本地,再取出展示在页面上
接收请求及浏览器传来的参数多媒体文件(MultipartFile fileImage)
多媒体文件保存到本地磁盘并返回给浏览器一个可访问图片的url地址
接收请求及参数(多媒体文件(MultipartFile uploadFile))
业务逻辑交给service层执行
controller中直接调用service层传参(多媒体文件)加载多媒体文件到服务器磁盘方法返回值时ImageVO对象
service层
从配置文件中获取到url地址及保存的服务器的物理地址
创建静态成员变量set集合(去重)存放图片文件的后缀名
静态代码块中为set集合赋值(图片的常用.后缀名)
定义将多媒体文件(图片)保存到服务器磁盘的方法并返回ImageVO对象(里面有图片的虚拟url访问路径,nginx中反向代理到本地磁盘真实访问路径即可)
1 通过多媒体文件调用getOriginFilename()方法获取图片文件的全名
2 字符串类型toLowerCase全部转化为小写
3 调用lastIndexOf(".")获取最后一个点的索引
4 根据索引切割字符串(包含了.)substring(index)获取到图片文件的.后缀
5 判断set集合中是否包含有该后缀,若没有则一定不是图片文件返回错误提示"用户上传的不是图片"
6 再创建BufferedImage对象,专门负责封装图片的工具类可以获取到图片的宽高属性
创建BufferedImage对象是通过图片IO对象ImageIO的API read方法获取到该多媒体文件的字节流封装为BufferedImage对象
通过bufferedImage对象获取宽高属性判断不为0即可
7 创建分目录存放图片的目录 --时间方式存储解析时间前后都要加斜杠
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
组合出真正的文件存放目录dirPath+dateDir封装为File对象imageFileDir --服务器存放路径+生成的时间分目录路径
8 实现文件上传
UUID.后缀 --realFileName(真正的文件存放名称)
封装为真正最终要存储的的文件对象(imageDir+realFileName) --imageFile
9 多媒体文件调用执行上传方法transferTo(imageFile),完成上传业务
10 动态生成url地址
String url = urlPath+dateDir+realFileName;
return ImageVO.success(url,width,height);
返回ImageVO对象即可
1.本地磁盘路径
D:/JT-SOFT/images/2020/09/04/21e815df0e1642a0adf417515b8c39b3.png;
2.网络虚拟路径
http://image.jt.com/2020/09/04/0714c3d41ac9409a934dff98f4a2db3a.png;
使用nginx反向代理即可实现访问虚拟url跳转到磁盘路径
备注:
在Linux系统中发布项目,文件存储路径也需要修改
#image.dirPath=D:/JT-SOFT/images
image.dirPath=/usr/local/src/images
image.urlPath=http://image.jt.com
Web项目创建
web服务器不需要连接数据库启动类注解上必须添加排除数据源配置!!
@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
打war包
pom文件继承依赖插件
前端不写直接导入
配置启动项
编辑web配置类 目的springMVC可以拦截以.html为结尾的请求.
@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
//开启匹配后缀型配置,为了将来程序实现静态页面的跳转而准备的
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true); //貌似这样拦截了所有的后缀类型了..
}
}
JsonP跨域应用JSONPObject(callback, itemDesc);对象实现数据对象自动转为json对象并拼接callback后返回给浏览器端
CORS跨域方式
common通用项目中添加cors配置类即可
1 配置类加注解@Configuration
2 必须实现WebMvcConfigurer接口
3 重写***addCorsMappings***(CorsRegistry registry)方法
添加拦截路径,可以跨域的域名及是否可以携带cookie参数
package com.jt.config;
@Configuration
public class CORSConfig implements WebMvcConfigurer {
/**
* 1.addMapping(/**) 允许什么样的请求可以跨域 所有的请求
* 2.allowedOrigins("*")可以允许任意的域名
* 3.allowCredentials(true) 跨域时是否允许携带cookie等参数
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") //"jt.com" ".jt.com"
.allowCredentials(true);
}
}
使用dubbo框架后
controller层添加@Reference(check = false, timeout= 3000)注解DI依赖注入Dubbo框架提供的第三方接口
yml配置文件中
server端口
spring的mvc前后缀
dubbo的包扫描,应用名称,注册中心
用户注册业务
controller层
接收请求及参数(用户信息对象)
dubbo远程调用service执行保存用户信息的方法
service层 sso服务器的
接收controller层用户信息对象
获取密码后使用DigestUtils对密码加密
password = DigestUtils.md5DigestAsHex(password.getBytes());
后将用户加密密码存入用户对象中
调用dao执行插入对象的方法
实现用户的单点登录
controller中
接收请求及参数(用户对象,HttpServletResponse response) //必须加上response对象因为需要它将cookie发送给浏览器端存储
调用dubboservice执行登录操作(参数用户信息对象)返回值是token令牌
检验令牌是否为空,为空则登陆失败
不为空则创建cookie对象将cookie名自己定义及token令牌存入cookie中
设置cookie的生命周期,哪个域名内共享,权限根路径
response.addCookie(cookie);将cookie存入到浏览器中
返回JsonResult的响应信息即可
sso系统中的service
接收用户对象参数
取出用户对象里面的密码,对其按统一的加密方式加密,加密后将密码存入用户对象中
创建条件构造器传入用户对象(传递的是对象会根据对象属性中不为null的值作为where条件查询)
调用dao执行查询操作若返回值为null则返回null给controller,用户登陆失败
若查询数据库数据不为null,用户信息正确开启单点登录
UUID生成token,将用户对象密码脱敏后存入redis缓存中,并设置缓存的生命周期返回给controllerToken即可
用户登出操作
controller层
实现用户的登出操作 要求删除cookie 和redis中的数据(key)
接收请求(自定义request,response对象)
通过request对象获取所有cookie[],判断cookie数组不为null不为0
遍历出每一个cookie取出名字与之前存入的cookie的名字对比有相同的就执行
通过cookie获取value值,(就是token)
根据token redis执行删除key操作删除token对应的缓存数据
再将cookie删除名字相同,生命周期设为0,其他参数设置与之前的一致即可删除
通过responde对象将cookie存入浏览器中 break;
最后重定向到根目录(登录页面)即可
商品详情展现 --前面不用dubbo时有一个url请求展现商品详情了query/item/desc/{itemId}这里是另一个url请求/items/{itemId}
controller中 web服务器中
接收请求获得参数商品id
调用service根据商品id查询商品信息
调用service根据商品iid查询商品详情信息
分别存入model中
返回商品页面
service层 manager服务器
实现dubbo框架接口
分别调用商品dao和商品详情dao执行查询操作
配置拦截器 --没有登陆的用户不能访问购物车 , 订单等
定义拦截器配置类
@Configuration
实现WebMvcConfigurer接口
重写configurePathMatch//开启匹配后缀型配置,为了将来程序实现静态页面的跳转而准备的
DI依赖注入自己写的拦截器
重写addInterceptors添加拦截器的方法(注册拦截器对象)
将自己写的拦截器注入到注册拦截器对象中,并设置拦截路径
registry.addInterceptor(userInterceptor).addPathPatterns("/cart/","/order/");
定义拦截器类
@Component交给spring容器管理
实现HandlerInterceptor接口
DI依赖注入进redis缓存中
重写前置过滤器方法
根据之前存入cookie的key(自己定义的)获取cookie中值token令牌
判断不为空则继续判断redis中token对应的数据对象是否存在,若存在则取出json数据对象,转化为数据实体类后存入request域中或者使用new一个本地线程变量对象后set存入数据实体对象到本地线程对象中,return true表示放行
否则若cookie中没有对应的token则将无效的cookie删除
重定向到登录页面后
return false; 表示拦截
重写后置过滤器
//1.删除Request对象的数据
//2.删除ThreadLocal中的数据
SSO单点登陆系统 --主要为web的服务器提供用户的数据的支持,但凡涉及到user的CRUD操作都应该由该系统完成
jar包
pom中继承依赖和插件
创建sso项目
用户的pojo类 继承BasePojo基础实体类
@TableName(“tb_user”)
@Data
@Accessors(chain = true)
@TableId(type = IdType.AUTO)
属性:
id,用户名,密码,电话,邮箱
controller层
接收请求,调用service执行查询用户信息的方法并返回list集合 --这里貌似加了@RestController后没有封装为JsonResult对象也是可以的
接收请求获取参数 (需要校验的参数param,校验的类型type,String callback) --这里是判断是否用户名电话邮箱是重复注册的
调用service层方法查询数据返回记录
返回JsonP跨域请求响应即可
return new JSONPObject(callback, SysResult.success(flag)); //flagservice返回的结果true/false
service层
定义成员变量map集合并用static修饰,将选择类型type一共三种静态代码块中都添加到map集合中
调用dao查询数据库查询所有用户信息list集合并返回
校验数据是否存在,查询总记录数即可,>0返回true,<0返回false
通过传来参数type通过map.get(type)获取到需要检验的字段
创建条件构造器条件是该字段等于param传来参数queryWrapper.eq(column, param);
调用dao查询记录数后判断即可
boolean flag = userMapper.selectCount(queryWrapper)>0?true:false;
返回flag
修改全局异常处理机制 --因为JsonP异常处理特殊
package com.jt.aop;
@RestControllerAdvice //作用: 标识我是一个通知方法,并且只拦截Controll层的异常.并且返回JSON.
public class SysResultException {
//JSONP的异常处理应该是 callback({status:201,msg:"",data:""})
//利用Request对象动态获取callback参数.之后动态封装返回值
@ExceptionHandler(RuntimeException.class)
public Object exception(Exception e, HttpServletRequest request){
e.printStackTrace();
String callback = request.getParameter("callback");
if(!StringUtils.isEmpty(callback)){ //jsonp请求
return new JSONPObject(callback, SysResult.fail());
}
//日志记录/控制台输出. 让程序员知道哪里报错!!!
return SysResult.fail();
}
}
使用dubbo框架后
service层实现类实现dubbo框架的第三方接口@Service注解是dubbo框架提供的
yml配置类中
server端口,根路径
spring数据源,mvc前后缀
mybatis-plus映射文件根路径,开启驼峰命名
logging日志debug配置
dubbo框架扫描包路径,应用名称,注册中心,指定传输协议dubbo及端口
用户登录回显
controller层
接收请求及传来参数token,自己定义上 HttpServletResponse response,String callback
查询redis中是否存在token,存在则取出用户对象
返回JsonP即可
return new JSONPObject(callback, SysResult.success(userJSON));
若查询缓存中没有对应的token
则删除原cookie(名字一样,生命周期为0,其他参数一样即可)
返回JsonP对象即可
return new JSONPObject(callback, SysResult.fail());
创建购物车模块
pom中添加继承依赖和插件
pojo类
@TableName(“tb_cart”)
@Data
@Accessors(chain = true)
继承BasePojo类
@TableId(type = IdType.AUTO)
属性:
id,用户id,商品id,商品卖点,商品图片,商品价格,购买数量
yml配置文件
server端口,根路径
spring数据源,mvc前后缀
mybatis-plus包扫描,开启驼峰命名
logging的debug配置
dubbo的包扫描,应用名称,注册中心,传输协议名字及端口
购物车列表展现
controller中 --貌似所有的web请求都可以放到web服务器中了
DI依赖注入dubbo框架的cart接口
接收用户请求传参(自定义Model对象,需要在request域中存数据)
获取用户id(通过request域或threadLocal本地线程对象获取)
根据用户id远程调用service查询购物车列表集合
存入model中
返回到cart页面即可
service层购物车服务器上了
@Service并实现dubbo的接口
接收controller传来的参数用户id
定义条件构造器条件是queryWrapper.eq(“user_id”, userId);
调用dao执行查询操作返回cart的list集合
返回即可
购物车数量修改
controller中 --web服务器上
接收请求及购物车信息对象
获取用户id,将用户id设置进购物车对象中
调用service执行更新操作
service层 --在购物车服务器上
接收cart信息对象
创建一个空的购物车对象,将传来参数的购物车对象中商品数量取出
创建条件构造器使用用户id及商品id一起作为查询条件
调用dao更新购物车信息(在这里以只有商品数量的空的购物车对象为修改对象, 购物车对象有的参数作为修改参数,空的参数原先的不动 --之前作为修改条件是把pojo对象作为构造器的条件,那样才是where条件,在这里是作为修改参数修改的!!)
购物车删除操作
controller层 --web服务器
接收请求及参数(购物车对象)
获取用户id
将用户id设置进购物车对象中
调用service层删除购物车
重定向到购物车列表页面
service层
接收传来的购物车对象
创建条件构造器将购物车对象传入构造器中
调用dao执行删除操作(这里以购物车对象中有的参数为条件执行删除操作)
购物车新增操作
controller层 web服务器中
接收请求及参数购物车对象
获取用户id,存入购物车对象中
调用service执行增加购物车的操作
重定向到购物车列表页面
service层 购物车服务器中
接收购物车信息对象
创建条件构造器将用户id和商品id作为where条件
调用dao执行查询操作
若查询出的信息对象为null则执行新增insert操作将购物车对象存入数据库中
否则只更新数量即可(通过购物车对象获取购物数量加上查询出数据库的对象获取到商品数量和存入到数据库查询出的对象中,再将该对象update更新到数据库中即可)
mapper接口 购物车服务器中
定义更新数量的方法即可(Update注解)
创建订单模块
pom文件中添加继承依赖和插件
yml文件
server端口,根路径
spring数据源,mvc前后缀
mybatis-plus包扫描,开启驼峰命名
logging的debug配置
dubbo的包扫描,应用名称,注册中心,传输协议名字及端口
订单确认页面展现
controller层 web服务器
DI依赖注入dubbo接口
接收请求
通过本地线程获取用户id
根据用户id远程调用service层执行查询方法查询出商品的list集合存入model中
返回订单列表页面
订单入库操作
controller层 web服务器
接收请求获取订单实体对象参数
本地线程获取用户id后存入订单对象中
远程调用service层执行订单存入数据库操作
return SysResult.success(orderId);
返回传参订单id成功响应即可
service层 订单服务器
接收controller层传来参数订单对象
字符串拼接根据当前时间毫秒值创建订单id
将订单id存入订单对象中,并设置订单状态为1
调用订单dao插入订单到数据库insert
通过订单对象获取订单物流信息对象并将订单id存入该对象中
调用订单物流dao执行insert操作插入订单物流信息入数据库
通过订单都西昂获取订单商品都西昂list集合
遍历list集合取出每一个商品将订单id存入其中后调用订单商品dao执行insert插入数据库操作
最后返回订单id即可
订单查询
根据orderId号,检索订单的数据信息.要求利用Order对象将所有的数据一起返回.
controller层 web服务器
接收请求及订单id编号
调用service根据订单id查询订单信息对象后存入model中
返回成功响应信息即可
service层 订单服务器
接收订单id参数
调用订单dao查村订单信息对象
根据订单id调用订单物流dao查询订单物流信息对象
构建条件匹配器以订单id为where条件
调用订单商品dao查询商品list集合
将查询出来的订单物流对象及订单商品对象都存入订单对象中返回给controller即可!!!
使用Quartz对超时订单处理
编辑配置类
package com.jt.conf;
@Configuration
public class OrderQuartzConfig {
/**
* 思想说明:
* 如果需要执行定时任务需要考虑的问题
* 1.任务多久执行一次. 1分钟执行一次
* 2.定时任务应该执行什么
*/
//定义任务详情
@Bean
public JobDetail orderjobDetail() {
//指定job的名称和持久化保存任务
return JobBuilder
.newJob(OrderQuartz.class) //1.定义执行的任务
.withIdentity("orderQuartz") //2.任务指定名称
.storeDurably()
.build();
}
//定义触发器
@Bean
public Trigger orderTrigger() {
/*SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(1) //定义时间周期
.repeatForever();*/
CronScheduleBuilder scheduleBuilder
= CronScheduleBuilder.cronSchedule("0 0/1 * * * ?");
return TriggerBuilder
.newTrigger()
.forJob(orderjobDetail()) //执行的任务
.withIdentity("orderQuartz") //任务的名称
.withSchedule(scheduleBuilder).build();
}
}
编辑定时任务
package com.jt.quartz;
//准备订单定时任务
@Component
public class OrderQuartz extends QuartzJobBean{
@Autowired
private OrderMapper orderMapper;
/**
* 如果用户30分钟之内没有完成支付,则将订单的状态status由1改为6.
* 条件判断的依据: now()-创建时间 > 30分钟 <==> created < now()-30
*
* sql: update tb_order set status=6,updated=#{updated} where status=1 and created< #{timeOut}
* @param context
* @throws JobExecutionException
*/
@Override
@Transactional
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
//1.利用java工具API完成计算
Calendar calendar = Calendar.getInstance(); //获取当前的时间
calendar.add(Calendar.MINUTE,-30);
Date timeOut = calendar.getTime(); //获取超时时间
Order order = new Order();
order.setStatus(6);
//order.setUpdated(new Date());
UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("status", "1").lt("created",timeOut);
orderMapper.update(order, updateWrapper);
System.out.println("定时任务执行");
}
}