校园商铺O2O小结

做完校园商铺平台O2O小项目1.0,项目来源慕课网,记录一下平时遇到的问题🤔:

项目简介:

项目1.0中使用SSM技术快速迭代出版校园商铺1.0;同时包含MySQL主从同步实现读写分离,利用SUI Mobile快速实现响应式页面,Redis缓存,数据库加密配置,部署上线等实用技术点。

数据库设计:

数据库表的总体结构如下:
全部实体类
注意:

  • 微信账号和本地账号是通过用户信息表中的user_id进行关联的,实现本地账号和微信账号的绑定。
    在这里插入图片描述
  • 店铺信息表跟以下四个表的关联:
    在这里插入图片描述
  • 商品信息表通过product_category_id跟商品类别表关联,通过product_id跟详情图片表进行关联
    在这里插入图片描述

    Logback日志框架:

    本项目中使用Logback日志框架,Logback 是 Slf4j 的原生实现框架,同样也是出自 Log4j 一个人之手,但拥有比 log4j 更多的优点、特性和更做强的性能,现在基本都用来代替 log4j 成为主流。

Thumbnailator图片处理:

GitHub链接地址
Thumbnailator是一个用来生成图像缩略图的 Java类库,可生成图片缩略图,支持根据一个目录批量生成缩略图,支持图片缩放,区域裁剪,水印,旋转,保持比例等等。
注意:需要封装工具类。

DTO及相关枚举类:

Data Transfer Object,即数据传送对象 。

DTO是一个普通的Java类,它封装了要传送的批量的数据。当客户端需要读取服务器端的数据的时候,服务器端将数据封装在DTO中,这样客户端就可以在一个网络调用中获得它需要的所有数据。

Shop实体类包含了Shop的基本属性,但是在前端操作时,我们希望可以返回操作的结果等信息,这个时候Shop实体类就不能满足需求了,我们将操作结果和Shop等信息统一放到DTO中处理,即可满足当前的需求。

DTO类ShopExecution:

package com.artisan.o2o.dto;

import java.util.List;

import com.artisan.o2o.entity.Shop;
import com.artisan.o2o.enums.ShopStateEnum;

/*
*DTO中还要包含操作商铺的返回结果,单个的实体类无法满足,所以封装到dto中,便于操作
*/
public class ShopExecution {
    private int  state ;
    private String stateInfo;
    private int count;
    private Shop shop;

    /**
     * 店铺集合 (查询店铺列表的时候用)
     */
    private List<Shop> shopList;



    //构造函数,店铺操作失败的时候使用的构造函数
    public ShopExecution(ShopStateEnum shopStateEnum) {
        this.state = shopStateEnum.getState();
        this.stateInfo = shopStateEnum.getStateInfo();
    }

     //构造函数,店铺操作成功的时候使用的构造函数
    public ShopExecution(ShopStateEnum stateEnum, Shop shop) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.shop = shop;
    }

      //构造函数,店铺操作成功的时候使用的构造函数
    public ShopExecution(ShopStateEnum stateEnum, List<Shop> shopList) {
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.shopList = shopList;
    }


    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getStateInfo() {
        return stateInfo;
    }

    public void setStateInfo(String stateInfo) {
        this.stateInfo = stateInfo;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public Shop getShop() {
        return shop;
    }

    public void setShop(Shop shop) {
        this.shop = shop;
    }

    public List<Shop> getShopList() {
        return shopList;
    }

    public void setShopList(List<Shop> shopList) {
        this.shopList = shopList;
    }

}

枚举类
使用枚举表述常量数据字典。例如为商品状态定义一个枚举类ShopStateEnum类。

package com.zzt.o2o.enums;


public enum ShopStateEnum {

    CHECK(0, "审核中"), OFFLINE(-1, "非法店铺"), SUCCESS(1, "操作成功"), PASS(2, "审核通过"), INNER_ERROR(-1001, "操作失败"), NULL_SHOPID(-1002, "ShopId为空"), NULL_SHOP_INFO(-1003, "传入了空的信息");

    private int state;
    private String stateInfo;

    private ShopStateEnum(int state, String stateInfo) {
        this.state = state;
        this.stateInfo = stateInfo;
    }


    public int getState() {
        return state;
    }

    public String getStateInfo() {
        return stateInfo;
    }

   // 定义换成pulic static 暴漏给外部,通过state获取ShopStateEnum
    public static ShopStateEnum stateOf(int state) {
        for (ShopStateEnum stateEnum : values()) {
            if(stateEnum.getState() == state){
                return stateEnum;
            }
        }
        return null;
    }

}

验证码kaptcha组件:

GitHub地址:
https://github.com/penggle/kaptcha

Kaptcha是基于SimpleCaptcha的开源项目。通过调整Kaptcha配置可以生成各种样式的验证码。

Kaptcha提供的功能如下:

  • 验证码的字体

  • 验证码字体的大小

  • 验证码字体的字体颜色

  • 验证码内容的范围

  • 验证码图片的大小,边框,边框粗细,边框颜色

  • 验证码的干扰线

  • 验证码的样式

jackson的使用

使用jackson将前端传过来的json数据格式转换为对应的pojo
GitHub:https://github.com/FasterXML/jackson-databind
在这里插入图片描述

商铺注册

设置图片:我的数据库中存储的并不是全部路径,而是部分路径,因此在传给前端路径时并不完全,因此我们在tomcat的server.xml文件中配置,解决方案:

在idea不想es直接更改,打开tomca文件夹找到server.xml文件在最后设置一个,意思相当于当我们遇到第一个参数的路径时转第二个路径就是当遇到/A就转为/A/B/C/这种

商铺编辑

Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的

注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下:<include refid=”namespace.sql片段”/>

商铺列表

列表页面需要支持分页 (MySql数据库,我们使用limit关键字)
在dao层:分页是这样的:我们接受的是limit start,size (start从0开始),在mapper文件中只能指定相应的从某行到某行,

从前端却只能传来页数和页数大小,因此我们需要一个页数转为记录条数的记录。
我们在Util类中写入一个方法,参数接受页数行页数大小,通过将页数减1乘上页数大小,就是我们要索引的这一页的所有记录。

商品类别

在删除商品类别时需要先将该商品目录下的商品的类别Id置为空,然后再删除该商品目录。

商品编辑

商品信息有商品缩略图和详情图片,我们约定好:如果用户传入了新的商品缩略图和详情图片,就将原有的商品缩略图和详情图片删除掉。

Redis使用:

加入缓存的配置步骤

  1. pom.xml 添加jedis依赖包
  2. redis配置文件
  3. spring-dao.xml加载redis.properties
  4. 封装JedisPool,用于创建JedisPool
  5. 封装操作redis的工具类 JedisUtil
  6. 新建spring-redis.xml 配置redis连接池和bean
  7. web.xml中加载spring-redis.xml
  8. Service层使用缓存

根据数据的特点,不经常变动的数据 即时性要求没有那么高的读数据 为了减轻DB压力,我们可以将数据放到缓存中。
目前我们需要将区域信息、商铺分类信息和头条信息放入到redis中。因为这些数据不怎么变化。同时注意需要将这些数据分类存储在redis中。
比如头条广告那里有区分是否可以放上去,即状态码
商品分类那里是否有子目录。
在这里插入图片描述

对信息数据加密

使用 DES 对数据库的用户名和密码进行加密。DES是一种对称加密算法。
步骤:

  1. DES工具类
  2. 修改配置文件中即jdbc.properties 中的用户名和密码
  3. 继承PropertyPlaceholderConfigurer,重写convertProperty方法
  4. 配置自定义的EncryptPropertyPlaceholderConfigurer

使用 MD5 加密算法 对用户信息进行加密。

SpringMVC 拦截器

  1. 对非法路径进行拦截,确保一个店家只能在一个店铺上进行商铺编辑,商品管理等。
    在这里插入图片描述

ShopPermissionInterceptor类:

package com.zzt.o2o.interceptor.shopadmin;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.zzt.o2o.entity.Shop;
/**
 * 商家不能去操纵不属于它管理的店铺
 * @author zhan
 *
 */
public class ShopPermissionInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        Shop currentShop = (Shop) request.getSession().getAttribute(
                "currentShop");
        @SuppressWarnings("unchecked")
        //从session中获取当前用户可操作的店铺列表
        List<Shop> shopList = (List<Shop>) request.getSession().getAttribute(
                "shopList");
        if (currentShop != null && shopList != null) {
            for (Shop shop : shopList) {
                //如果当前店铺在可操作的列表则返回true,进行接下来的用户操作
                if (shop.getShopId() == currentShop.getShopId()) {
                    return true;
                }
            }
        }
        //不满足返回false
        return false;
    }
}
  1. 如果路径非法(没有经过登录)直接访问路径名,也将跳到登录界面。
    在这里插入图片描述

ShopLoginInterceptor类:

package com.zzt.o2o.interceptor.shopadmin;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.zzt.o2o.entity.PersonInfo;
/**
 * 店家管理系统登录验证拦截器
 * @author zhan
 *
 */
public class ShopLoginInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        Object userObj = request.getSession().getAttribute("user");
        if (userObj != null) {
            PersonInfo user = (PersonInfo) userObj;
            if (user != null && user.getUserId() != null
                    && user.getUserId() > 0 && user.getEnableStatus() == 1)
                return true;
        }

        //若不满足登录验证,则直接跳转到账号登录页面
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<script>");
        out.println("window.open ('" + request.getContextPath()+ "/local/login?usertype=2','_self')");
        out.println("</script>");
        out.println("</html>");
        return false;
    }
}

   转载规则


《校园商铺O2O小结》 ForeverSen 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
LeetCode中BFS&DFS LeetCode中BFS&DFS
深度优先遍历DFS: 假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选
2019-05-02
下一篇 
LeetCode中常见的链表题目 LeetCode中常见的链表题目
开始对LeetCode中链表相关问题进行刷题🤔 206. Reverse Linked List题目描述:反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL输出: 5->4-&g
2019-04-28
  目录