1 Star 0 Fork 0

hujun / Mall

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

商城项目

1.技术栈

springboot + mybatis

2.如何上手一个新的项目

千万记得配置好数据库连接信息,以及在数据库中建好表。

如果把配置文件的东西注释了,启动不了的话,需要看console的报错信息。

启动项目,不同于ssm通过tomcat启动,而是通过application类启动。浏览器输入相应的地址和端口,就能打开了

3.常见问题

通过浏览器F12进行一些信息的查看

跨域问题:CORS error 通过浏览器控制台和network可以看到错误信息,问题在于localhost和127.0.0.1是不同的两个域,所以需要特别注意输入的域名,否则就有跨域问题

Postman可以在无前端的情况下,通过访问url进行信息反馈 Swagger可以把实现的接口全部显示出来,方便调试。自动生成API文档

这就是前后端分离的开发情况。

Springboot已经预放了很多依赖(默认配置)

利用AOP将controller的请求之前和之后的信息都记录到文件中,方便错误排查。

4. 各模块的开发

1.用户模块

  1. 接口文档地址: https://shimo.im/docs/K3WhpQ33RcqvkdyD/read

  2. 根据接口文档来实现后端的开发过程,就可以在没有前端的情况下,把后端的功能开发好。

  3. API统一返回对象,在前面的SSM项目中,采用Map对象的形式返回处理数据(个人编码风格不同) common包:放一些通用的类

java基础语法:

1.泛型 2.private static final作用 https://www.cnblogs.com/notably/p/11791542.html 3.构造方法 3.枚举类

对于这个统一返回对象的理解: 前端接收的是一个JSON格式的信息数据(状态码,信息,数据),这就意味着后端需要把数据打包成一个返回对象,每个请求返回的JSON数据都可能不一样。为了更好的统一管理,将这个返回的信息封装成一个对象。需要时,往这个对象里赋予相应的数据即可,然后返回这个对象给前台。

对于错误信息来说,这就涉及到异常相关。错误信息太多,因此可以选择在一个枚举类中把他们都枚举出来,然后用的时候直接选择相应的错误信息即可。 具体如何调用,看后面的代码

注册接口的开发: @RequestParam("userName")String userName,@RequestParam("password")String password @RequestParam的作用:? 将url里面的参数名的值,赋予String xx这个自定义变量参数

这个数据库语句有点不理解,插入多参数时,怎么用? 动态sql语句

统一异常处理: 抛出异常,直接转换为JSON的APIResponse 把业务和系统异常拦截后统一通过API返回JSON统一处理。防止一些其他的错误信息返回给浏览器,造成安全问题。

Java异常体系: 错误:无法处理 异常:自己的问题,需要处理

public Object:?

密码MD5保护: MessageDigest.getInstance();? 先变成MD5形式,然后加盐

登录接口的开发: 登录校验 登录状态需要保持:session的实现方案,会保存用户信息到session.之后的访问,会先从session中获取用户信息,然后再执行业务逻辑

对于mybatis而言: User selectLogin(@Param("userName") String userName, @Param("password") String password); @Param的作用: https://blog.csdn.net/Sunshineoe/article/details/114697944

多参数时:parameterType="map"

这里没有开启驼峰命名转化的,所以会出现实体类和数据库字段名不匹配的错误 解决办法:利用map映射,将他们一个个全部隐射好。 这种更为基础的方法,刚开始侧重学习一下,简便方法,学多了容易出问题 标签:

  <select id="selectByName" parameterType="String" resultType="com.springboot.mall.model.entity.User">
    select * from mall_user where username = #{value}
  </select>

"include refid="Base_Column_List"" https://blog.csdn.net/weixin_42153410/article/details/100136536

@Override注解的作用: https://blog.csdn.net/weixin_45797022/article/details/120815533 代表这个方法是是实现了父类的方法 退出登录的接口开发

Swagger自动生成API文档: http://localhost:8083/swagger-ui.html

商品分类模块: public class AddCategoryRequest 为什么特意写这个类,而不直接使用实体类,因为传入的参数,只需要部分实体类的参数。查询语句如果判断出有新的参数传过来了,会进行修改,造成信息被篡改的安全风险,所以单独拿出来,避免这种安全风险问题的出现。

服务层抛出异常,控制层返回处理结果

@RequestBody AddCategoryRequest addCategoryRequest 数据是从body中传过来的,所以需要增加这个注解

参数校验注解: @Valid 需要验证 @NotNull 非空 @Max(value) 最大值 @Size(max,min) 字符串长度范围限制 message="可以描述自己定义的限制信息"

在全局异常处理类中,增加了参数异常处理,把异常信息封装并返回给浏览器

更新目录接口开发: 更新逻辑有一些些绕,仔细顺一下。 //首先判断 更新的名字是否在数据库中已经存在(名字不能重复) //如果不为空,则数据库已经存在该名字,但是如果知识想更新这个名字的层级,则必然是可以查到这条数据的 //所以需要验证这条数据的id和传过来的id是否一致

统一校验管理员身份: 增加目录,和更新目录都复用了一段代码(校验管理员的身份) 过滤器的作用:(看一下前面的视频,查一下资料也可以,了解一下概念) 拦截作用: //还未进入controller进行拦截过滤的操作

相当于把这个校验操作交给了过滤器,并进行了配置,将这段代码分离出去了。

请教一下关于过滤器,拦截器,监听器具体应用上的区别? - Java3y的回答 - 知乎 https://www.zhihu.com/question/35225845/answer/1165331090

输入输出流: out.flush(); out.close();

网络通信: HttpServletResponseWrapper:

删除目录接口开发: (根据id进行删除)id不存在不允许删除

(!!!!!)管理员分页功能开发:(重中之重!!!!!) 好好理解这个代码逻辑以及实现方式 VO包:经过处理而转换而成的类 利用分页插件pagehelper(pom.xml引入依赖)

用户分类列表接口开发:(重要的知识点!!!!) 通过接口文档可以看出,有一个childCategory{},也就是说,有些大目录下包含着很多子目录,这也就是为什么要创建CategoryVO类的原因了,增加了子目录集合属性,使得该对象可以保存自己子目录的所有信息 思考一个问题: 这个多级目录结构采用递归实现,递归算法效率低,如何把这个操作改为非递归实现(有难度,需要思考!!!) 这是一个有难度可以深挖的点: https://www.52gh.top/code/java_listtotree.html https://zhuanlan.zhihu.com/p/420281778

这个双重循环的方式使用的就是非递归的方式。 http://www.zyiz.net/tech/detail-119400.html

成功实现了这个非递归的方法,有点小缺陷。不过通过请求测试,非递归的请求响应时间会比递归的短一半左右。

ArrayList<>()相关的知识点:

利用Redi缓存加速响应: springboot集成redis 得先安装一下redis,在前面的课程里面有。(学习一下) win版redis Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝,无法连接。 https://blog.csdn.net/weixin_48333575/article/details/123267599

1.redis-server.exe redis.windows.conf 2.redis-cli.exe -h 127.0.0.1 -p 6379 或者redis-cli 每次都要这样启动一下,或者让它长期驻在后台,始终不关闭(没必要)

IDEA调试技巧: 调试技巧也很重要 断点统一开关 条件断点 单步调试 表达式求值

gitee贡献度为啥不记录我的更新提交(测试):绑定了邮箱才能记录提交次数

学的太快,跟着敲一遍,很多东西只有印象,不熟悉,可以选择一两个重要的模块进行研究通透。 也不急,先上车后补票,多巩固两遍就熟悉了。(你不可能对一个项目各个方面都熟悉,所以挑一两个模块搞得透彻一点) (比如问你最熟悉的模块是什么:分页(管理员分页,和用户界面分页不一样,这个模块可以展开来细说,然后解决用户响应慢得问题,引入redis,知识点连成串了),日志AOP(主要是涉及AOP知识的应用,可作为熟悉的一个准备))

今天遗留下的问题都解决一下。再开始下一个模块的开发。

List<Map<String, Object>> 这个基础知识也是需要补充一下的

看了别人的代码,有一个感悟,每一个人写的代码风格和方式都是不一样的,先模仿,学习,然后形成自己的代码风格。 看别人的代码,学习他的思路,而不是学习他的编写风格。基于自己的代码风格,实现他人的思路。 不同的代码风格,看起来的理解程度也不同,需要掌握好基础内容,才能更加灵活。

多看,多学,多思考,多模仿!!!

商品模块:

商品添加接口: 通过API文档,看看这个请求传递了哪几个参数,然后定义一个新的实体,并对这个新的实体进行参数校验 接着写controller中的实现操作

有一个问题,前端如何传递图片字段呢? UUID介绍: 文件名UUID,通用唯一识别码(防止重名,防止爬图) 生成规则:日期时间,MAC地址,HashCode,随机数 (也就是将传上来的图片给它一个唯一的名字,这个名字是按照UUID规则生成的)

图片上传接口开发: @Value注解:?

实现逻辑:

  1. 将上传的file获取,获取它的整体文件名
  2. 然后通过这个整体的文件名截取.后面的文件类型
  3. 通过UUID生成一个新的文件名前缀
  4. UUID和文件类型组装成一个新的唯一的file文件

创建文件:

定义一个文件夹用来保存file(配置地址) 生成文件

图片上传逻辑挺复杂的,也挺常用的,着重理解与记忆。

资源映射开发:

开发经验初总结:开发过程中的需求与业务逻辑,不可能全部都会的。遇到不会的可以选择在gitee,github上找相同的开源项目,对应的模块进行借鉴。从而解决自身问题。其他的多用搜索引擎,一个一个解决,别怕。 就像这个商城项目,学过一遍肯定更加熟悉其中的一些操作,找相同的开源项目,找到对应的模块,会发现基本都差不多,看看修改修改然后完成自己的需求。

这只是针对业务逻辑需求可以这么干,对于框架的使用以及bug需要自己花时间一步一步学上来。

准备面试的时候,可以多看看别人的项目,熟悉看别人项目的技巧也很重要(可以看一看比较今典的几个项目,或者看看Spring JPA)

5.13 学习git创建分支,为每一个模块的分支创建不同的分支。最后学习把他们合并到一起。 6的开发部分

分支测试:product/hujun

product/hujun: 图片上传功能的开发 自定义静态资源映射目录: 上传图片后回显:访问URL可以查看图片 配置WebMvcXConfig 静态资源到本地目录的映射 打开图片

商品更新操作,简而言之,需要判断是否更改了商品名字(唯一)。如果更改了需要判断是否重名

删除产品在实际业务中不是很推荐,需要保留相应的数据,实际会采用下架操作来代表删除

批量上下架商品:(有难度) MyBatis遍历List where语句拼接

商品列表后台:(分页)

前台商品列表:(搜索功能,这个功能开发挺复杂的) 入参判空->加%通配符->like关键字 (此功能是有选择性的展示用户需求的数据)

目录处理:如果查某个目录下的商品,不仅是需要查出来该目录的,还需要查出来子目录的所有商品 所以这里要拿到某一个目录id下的所有子目录id的list //StringBuffer()合成字符串用的 pull新的远程分支,会发现变成最原始的master的部分

5.14 购物车模块开发:

业务流程: 添加商品到购物车(流程比较复杂)

商品在售,是否有库存,没有库存,提示用户无库存,有库存则判断用户是否已经添加过购物车,已经添加了则在原有数量的基础上递增。没有添加过,则添加商品

一个问题:获取用户购物车列表的时候,并没有携带用户信息,如何判断该查询哪个用户的购物车呢,这就需要一个购物车的过滤器,筛选用户。 添加商品时,依照原来的逻辑,直接添加即可,然后刷新,后台再调用一次查询接口,增加了延迟。所以选择CartVO实体,直接添加操作后,返回所有需要的数据。减少延迟

(购物车的逻辑理解很重要)

多线程安全问题+鉴权框架(这是两个可以完善的点,和需要考虑的点) 良好的程序员优先考虑的不是业务逻辑,而是兜底的异常方案!!!

自己给自己提需求,然后解决。不要急,不要怕,刚开始都是这样的,一步一步进步就好了。

闭门造车不可行,是学不完的,差不多的掌握了,直接进入真实场景进行学习。

5.14 下午 购物车列表 //内部获取用户ID,防止横向越权 横向越权:用户之间相互访问对方的信息 纵向越权:用户访问管理员的权限操作

select id, identity, from mall_cart c left join mall_product p on p.identity = c.product_id where c.user_id = #{userId,jdbcType=INTEGER}

sql语句的左连接语句(熟悉sql语句的用法) 多表关联查询

更新删除购物车接口开发:

购物车的单选与全选:

订单模块开发:

image-20220516192323013

image-20220516192604318

image-20220516192649121

image-20220516192703519

注意这个超卖和事务管理的操作,面试问的概率很大。这个模块得弄熟来。这个订单模块可以套用到很多系统中(商城,外卖等)

订单传入的参数比较复杂,所以采用一个请求类把要传递的参数包装起来:id ,orderNo不是前端传过来的,而是自己生成的。userId是自己获取到的,totalPrice是算出来的。

前端传入收件人信息,电话,地址。在现在的商城系统(淘宝,美团)中是通过传入用户选择的地址编号,来查询出这三个信息(参考开源商城项目,把这一模块弄得更加完善,更加贴近现实项目)

orderService:

用户创建订单,因此订单有一个表,每个订单会有很多商品,所以需要把创建订单时所勾选的商品记录到订单商品表中。

对于拿到已经勾选的购物车商品信息,复用购物车信息列表mapper,然后利用循环选出来是一种办法。直接写一个挑选mapper,直接调用也可以,看个人编码风格。

创建订单过程需要添加数据库事务:

整个代码逻辑过长,如果中间哪一步出错,就会造成数据库数据的混乱。

从测试来看,一旦创建订单失败(传入的必选值没有,然后会把购物车的已选的删除,但是创建订单失败)

//遇到什么异常都会回滚
@Transactional(rollbackFor = Exception.class)

空文件

简介

取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/spacehj/mall.git
git@gitee.com:spacehj/mall.git
spacehj
mall
Mall
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891