# xiaomishop **Repository Path**: zhang-xuerui/xiaomishop ## Basic Information - **Project Name**: xiaomishop - **Description**: 完成订单详情 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-02-28 - **Last Updated**: 2022-02-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基本定义 ## 项目定义 > 我们的项目会有很多个不同的功能,我们采用的是单体MVC架构,需要划分不同的包 > 1.所有和servlet相关的类我们都使用controller包 > 2.所有和业务相关的使用service包,实现类采用impl包 > 3.所有的和数据库相关操作的使用dao包 > 4.所有和数据库对象相关的类使用domain或者pojo 或者entity或者bean都可以 > 5.如果有工具类 放到utils > 6.过滤器放到filter包 > 7.所有的监听器放入到listener包 ## baseServlet > 由于servlet是一个重量级的组件,需要经过注册,初始化等等生命周期 > 所以我们为了减少资源的占用,采用一个servlet处理所有的请求,通过我们定义的映射规则来分发到不同的类的不同方法 ## 返回值的问题 > 我们的返回值基本上就三种,一种是转发,一种的重定向,一种是返回数据,几乎所有的接口都是这样的 > 我们约定,如何区分三种格式的数据,然后在baseServlet中进行统一处理 ## 注册登录 > 密码的安全问题,数据库中严禁存放明文密码,我们需要存放的是所谓的"密文" > 比如存放MD家族的数据MD5或者SHA家族的SHA1 SHA128 SHA256 SHA512 > 就代表着我们在注册的时候需要将用户输入的密码先转成MD5,然后再插入到数据库,查询的时候一般先用用户名查询,查询出来之后吧和用户传递的密码转成MD5再和 > 查询到的密码进行比较 ## 事务的问题 > 什么是事务?一个业务的数据库的操作的执行,要么全部成功,要不全不成功(成功与否取决于业务的要求,比如这个业务中有是个数据库的操作,我们要求前面八个必须一起成功或者失败,后面两个失败不影响前面的八个),多个sql操作如果出现了失败 > 要想全都失败,必须执行rollback代码,如果十个操作,前面八个成功了,后面两个失败了,如果想都失败,执行rollback,如果执行commit,前面八个会成功 > 事务的隔离级别:读未提交,读已提交,可重复读,串行化 > 事务的四个特性:原子,一致,持久,隔离 > 一致性:sql的预期结果和最终结果保持一致,并且没有破坏列的约束性 > 事务不提交,数据在不在数据库中?在,只是没有持久化保存到磁盘上,在缓冲区中 ## 分类相关的操作 ### 查询分类 > 我们的首页会显示分类数据,我们需要获取到分类数据,在首页进行显示 #### 问题 > 我们发现我们很简单就可以查询到分类,但是我们发现我们每次请求header.jsp页面都会加载一次分类数据,并且每次都要查询数据库 > 但是我们每次返回的数据都是一样的,也就是我们查询一次数据库和查询N次结果相同,这样就会导致N次无效查询,实际上我们只需要查询一次就可以了 > 怎么解决?缓存,在另外一个地方临时保存一份数据的副本,和原始数据一样的数据,但是这个数据不在数据库中,在内存中,内存速度远远的高于磁盘速度,我们的数据库不支持高并发,磁盘速度有限,我们要降低数据库的访问量,经过分析,我们的缓存数据在服务器启动完成的时候 > 就应该有了,那我怎么知道服务器启动完成了呢,监听器可以知道服务器在启动,我们在监听器的代码中查询分类数据,然后保存到缓存中 > 缓存在什么地方?在listener中进行保存,在servlet中获取,所以这个数据需要在多个类之间共享 > 我们学到的技术一般就是单例对象的变量,另外一个是静态变量,还有一个地方可以共享,servletContext > > 我们遇到了一个问题. 就是在监听器中初始化缓存的时候如果缓存需要的时间稍微长一点,那么会导致服务器启动阻塞,因为初始化数据的操作和启动的操作在一个线程中 > 我们可以使用新的线程的方式去加载缓存,主线程不会阻塞, 什么时候我们会用到新线程,非核心操作或者不影响整体使用的操作可以放入到子线程 ### 添加分类 > 要完成一个功能,需要经过servlet, service, dao 先写谁? 先写谁都可以, 如果你要先定义接口相关的东西,写servlet,要先考虑业务的东西,写service,有表,先写sql语句就写dao > 经过测试,发现添加分类可以运行,但是缓存中的数据没有变化,我们需要更新缓存,但是后面如果有更新和删除都需要更新缓存 > 我们需要封装代码,进行调用,有点麻烦,实际上我们的目的是不是只要更新缓存就行了,我们是不是只要告诉缓存,兄弟我更新数据了,要不你自己更新下? > 单一职责,谁的事情谁负责,不要干太多超出自己职责的事情,只要通知就可以,有什么技术可以实现通知, listener ### 查询分类商品数据 > 根据分析查询某个分类的商品必须要传递分类id,服务端接收到数据之后,根据分类查询数据,但是数据可能会比较多,一次显示有点多 > 我们会按照分页返回,那就要求用户必须传递是第几页,可能还需要传第一页显示多少数据 > 我们约定,分页的数据不传递的情况下,使用默认值,第一页,显示10条 > 剩下的就是根据分页数据计算sql中的偏移量 limit x,y 还要计算页数,我们还需要知道总条数,偏移量(页数-1)*每页的数量 > 总条数n,每页显示的数量y,就可以计算出总共需要多少页(n-+y-1)/y > 可以找一个类,在类中声明数据,总条数,每页的数量,当前的页码 ### 购物车 > 把一些我们想要买的数据临时保存起来,方便后面查看或者统一下单,购物车中保存商品的id和数量就可以了,因为购物车中的数据是而可以变化的 > 添加购物车其实就是给购物车中添加了几个列,商品的id,一个数量,购物车中应该还有一个列,用户的id ### 查看购物车 > 用户只能看自己的购物车,所以需要一个参数就是用户的id,但是实际上用户的id我们可以自己获取,不需要传递 > 我们只需要在代码中获取到当前登录的用户的id就可以了 ### 订单 > 订单是记录某个用户在什么时间购买了什么商品,多少得数量,邮寄到什么地方等,还包括基本得信息比如是否支付 > 订单和用户有关联,和商品有关联,和地址有关联 > 订单和用户是多对一,就应该在多的一方中有一个外键列 > 订单和商品是多对多得关系,存在一个中间表 > 订单和地址是什么关系,多对一得关系,也是在多的一方保存一个外键列 ## 监听器 > 8个监听器 > servletcontext相关的两个,一个监听启动,一个向servletcontext中存放数据 > request相关两个,一个监听请求创建和销毁,一个监听向request存放数据 > session的四个,一个监听创建销毁,一个监听向session存放数据,一个监听session钝化和活化,最后一个严格上来说是给对象设置的,是让对象自己知道被放到了哪个session中