GitHub mall项目学习(二) mall-admin

GitHub mall项目学习(二) mall-admin

本文主要介绍mall-admin后台系统

mall
├── mall-common -- 工具类及通用代码
├── mall-mbg -- MyBatisGenerator生成的数据库操作代码
├── mall-security -- SpringSecurity封装公用模块
├── mall-admin -- 后台商城管理系统接口
├── mall-search -- 基于Elasticsearch的商品搜索系统
├── mall-portal -- 前台商城系统接口
└── mall-demo -- 框架搭建时的测试代码

简介

本文主要介绍mall-admin,后台管理系统模块,该模块涉及最多的为业务逻辑处理,即常规的CRUD开发,但其中有很多值得学习的处理方案,本文将列举并详细介绍这些方案

controller

后台项目包含的controller,通过前缀区分,Sms为营销管理,Oms为订单管理类,Pms为商品管理类,Ums为后台用户管理类,还有一些其他类

其他如pojo,返回结果封装等均为常规套路,此处不做介绍,请阅读mall-common中api包中的内容

技术点

PageHelper页面分页助手

所以controller需要的分页返回实现均使用PageHelper插件实现.

插件依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <!-- 	mybatis的很多依赖都喜欢这样写-。-	-->
    <version>最新版本</version>    
</dependency>

application.yaml配置

#分页pageHelper
pagehelper:
 # sql方言  默认也会自动检测
  helper-dialect: mysql
 # 配置分页合理化,查询页<1,会返回第一页,查询页>最大页,会返回最后一页     默认false
  reasonable: true
  support-methods-arguments: true

使用

// 主要是service中使用
public Object getUsers(int pageNum, int pageSize) {
    	// 这句话说明返回页和每一页数量
        PageHelper.startPage(pageNum, pageSize);
        // 不带分页的查询
        List<UserEntity> list = userMapper.selectAllWithPage(null);
        // 将list转换成页面数据,该数据就包含了本页信息以及一些详细信息
        PageInfo<Apps> appsPageInfo = new PageInfo<>(list);
        return list;
}

原理(涉及Mybatis的一些细节,之后会发相关文章!~~~)

是通过实现Mybatis的Interceptor接口

pageHelper会使用ThreadLocal获取到同一线程中的变量信息

利用这一点通过拦截器获取到同一线程中的预编译好的SQL语句之后将SQL语句包装成具有分页功能的SQL语句,并将其再次赋值给下一步操作,所以实际执行的SQL语句就是有了分页功能的SQL语句

  1. 先解析各位置参数
  2. 初始化 pageHelper 实例, 即 dialect;
  3. 调用方法判断是否需要进行分页,如果不需要,直接返回结果;
  4. 判断是否要进行count, 如果需要则实现一次count, ;
  5. 查询分页结果;
  6. 封装带分页的结果返回;

通过反射实现相同类型插入数据库操作方法的封装

案例:在添加商品时会涉及很多的模块,如该商品有阶梯价格,满减价格,需要关联主题,SKU库存插入,关联优选,而这些操作都是相同的操作,及添加一条记录(商品id:xxx,关联信息数组),很多数据首先要关联商品id,再插入数据库,都是重复操作,所以封装成一个基于反射的方法,获取每种类型中的setProductId来为这条记录设置商品id

/**
     * 建立和插入关系表操作
     * @param dao       可以操作的dao
     * @param dataList  要插入的数据
     * @param productId 建立关系的id
     */
private void relateAndInsertList(Object dao, List dataList, Long productId) {
    try {
        // 如果该数组为空,说明添加时并没有插入内容,直接返回
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }
        // 变量list数据
        for (Object item : dataList) {
            // 通过反射获得该Dao的setId方法
            Method setId = item.getClass().getMethod("setId", Long.class);
            setId.invoke(item, (Long) null);
            // 通过反射获得该Dao的setProductId方法,将要添加的商品id绑定给这条记录
            Method setProductId = item.getClass().getMethod("setProductId", Long.class);
            // 绑定id
            setProductId.invoke(item, productId);
        }
        // 反射获得dao的插入数据方法,将这些记录插入数据库
        Method insertList = dao.getClass().getMethod("insertList", List.class);
        insertList.invoke(dao, dataList);
    } catch (Exception e) {
        LOGGER.warn("创建产品出错:{}", e.getMessage());
        throw new RuntimeException(e.getMessage());
    }
}

添加商品时使用,很多表的插入都是直接使用该方法

@Override
public int create(PmsProductParam productParam) {
    int count;
    //创建商品
    PmsProduct product = productParam;
    product.setId(null);
    productMapper.insertSelective(product);
    //根据促销类型设置价格:会员价格、阶梯价格、满减价格
    Long productId = product.getId();
    //会员价格
    relateAndInsertList(memberPriceDao, productParam.getMemberPriceList(), productId);
    //阶梯价格
    relateAndInsertList(productLadderDao, productParam.getProductLadderList(), productId);
    //满减价格
    relateAndInsertList(productFullReductionDao, productParam.getProductFullReductionList(), productId);
    //处理sku的编码
    handleSkuStockCode(productParam.getSkuStockList(),productId);
    //添加sku库存信息
    relateAndInsertList(skuStockDao, productParam.getSkuStockList(), productId);
    //添加商品参数,添加自定义商品规格
    relateAndInsertList(productAttributeValueDao, productParam.getProductAttributeValueList(), productId);
    //关联专题
    relateAndInsertList(subjectProductRelationDao, productParam.getSubjectProductRelationList(), productId);
    //关联优选
    relateAndInsertList(prefrenceAreaProductRelationDao, productParam.getPrefrenceAreaProductRelationList(), productId);
    count = 1;
    return count;
}

全局异常设置

该项目使用@ControllerAdvice + @ExceptionHandler(value = xxx.class)来实现全局异常控制,当controller抛出异常后,会被该类捕获到,并做对应的处理

// 注解表示该类为全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
    // 返回json
    @ResponseBody
    // 捕获对应的异常
    @ExceptionHandler(value = ApiException.class)
    public CommonResult handle(ApiException e) {
        if (e.getErrorCode() != null) {
            return CommonResult.failed(e.getErrorCode());
        }
        return CommonResult.failed(e.getMessage());
    }
}

AOP实现接口信息统计

@Aspect 定义一个切面类

@Pointcut(“execution(public * com.macro.mall.controller..(…))||execution(public * com.macro.mall..controller..*(…))”) 定义一个切入点,这里表示controller层的方法都被增强

@Around(“pointcutxxx”) 定义一个环绕方法

用于封装需要记录的日志信息,包括操作的描述、时间、消耗时间、url、请求参数和返回结果等信息。

@Around("webLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    long startTime = System.currentTimeMillis();
    //获取当前请求对象
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();
    //记录请求信息(通过Logstash传入Elasticsearch)
    WebLog webLog = new WebLog();
    Object result = joinPoint.proceed();
    Signature signature = joinPoint.getSignature();
    MethodSignature methodSignature = (MethodSignature) signature;
    Method method = methodSignature.getMethod();
    if (method.isAnnotationPresent(ApiOperation.class)) {
    ApiOperation log = method.getAnnotation(ApiOperation.class);
    webLog.setDescription(log.value());
    }
    long endTime = System.currentTimeMillis();
    String urlStr = request.getRequestURL().toString();
    webLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));
    webLog.setUsername(request.getRemoteUser());
    webLog.setIp(request.getRemoteAddr());
    webLog.setMethod(request.getMethod());
    webLog.setParameter(getParameter(method, joinPoint.getArgs()));
    webLog.setResult(result);
    webLog.setSpendTime((int) (endTime - startTime));
    webLog.setStartTime(startTime);
    webLog.setUri(request.getRequestURI());
    webLog.setUrl(request.getRequestURL().toString());
    Map<String,Object> logMap = new HashMap<>();
    logMap.put("url",webLog.getUrl());
    logMap.put("method",webLog.getMethod());
    logMap.put("parameter",webLog.getParameter());
    logMap.put("spendTime",webLog.getSpendTime());
    logMap.put("description",webLog.getDescription());
    //        LOGGER.info("{}", JSONUtil.parse(webLog));
    LOGGER.info(Markers.appendEntries(logMap), JSONUtil.parse(webLog).toString());
    return result;
}

Redis缓存处理策略

  • 定义RedisService类来封装了RedisTemplate的方法
  • 定义UmsAdminCacheService类来封装用户缓存方法,为什么要有这一层主要是为了封装好Redis中Key的自动设置
  • 定义RedisAOP切面,将每个缓存方法都添加try-catch块,这样做避免了重复书写,并且在Redis宕机时,不管调用哪个缓存方法,都会接收到通知信息(此处内容被定义到了mall-security模块中,因为该缓存主要时用户权限控制时使用)
  • 自定义CacheException注解,在AOP增强方法时,先扫面该方法的注解,如果有该注解,就会直接抛出错误,而不是只进行记录日志

其他

该模块介绍中很多技术其实使用了mall-common或者mall-security模块中的内容,后续会出mall-security

免了重复书写,并且在Redis宕机时,不管调用哪个缓存方法,都会接收到通知信息(此处内容被定义到了mall-security模块中,因为该缓存主要时用户权限控制时使用)

  • 自定义CacheException注解,在AOP增强方法时,先扫面该方法的注解,如果有该注解,就会直接抛出错误,而不是只进行记录日志

其他

该模块介绍中很多技术其实使用了mall-common或者mall-security模块中的内容,后续会出mall-security

本专题并不详细记录curd细节(除非很必要),主要介绍一些经典的技术点!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: mall-admin-web-master 是一个商城管理系统的前端项目。该项目采用了现代化的前端技术栈,包括 Vue.js 框架、Element-UI 组件库等,以提供一个用户友好、功能强大的商城管理界面。 mall-admin-web-master 的主要功能包括用户管理、商品管理、订单管理以及数据统计等。用户管理模块可以对商城用户进行增删改查操作,包括用户信息、权限设置等。商品管理模块可以对商城商品进行管理,包括商品录入、编辑、上架、下架等操作。订单管理模块可以对商城订单进行管理,包括订单查询、订单发货、订单退款等操作。数据统计模块可以对商城的销售数据进行统计和分析,为商城经营提供参考依据。 mall-admin-web-master 还具备一些高级功能和技术特点。通过与后端 API 的交互,实现与商城后台的数据同步和交互。支持响应式布局,可以适配不同设备的屏幕尺寸,例如电脑、平板和手机。利用前端路由技术,实现了页面之间的无刷新切换以及浏览器的前进后退功能。同时,该项目还具备良好的代码结构和可扩展性,可以方便地进行二次开发和定制。 mall-admin-web-master 是一个非常实用的商城管理系统前端项目,通过它,商城管理员可以方便地进行各项管理操作,并获取有关商城经营情况的统计数据,为商城的运营提供支持和决策依据。 ### 回答2: mall-admin-web-master 是一个项目文件夹的名称,通常是指商城后台管理系统的前端代码。这个项目包含了商城后台管理系统所需的各种功能和页面,利用这些代码可以搭建起一个完整的商城后台管理系统。 mall-admin-web-master 的代码主要使用了前端开发技术,例如HTML、CSS和JavaScript等。通过这些技术,开发者可以创建出用户友好、美观且功能强大的商城后台管理页面。 商城后台管理系统是为了方便管理员管理商城运营而开发的一个系统。它包括了商品管理、订单管理、用户管理、数据统计分析等各种功能模块,通过使用这个系统,管理员可以方便地管理商城的运营和销售数据,提升工作效率。 mall-admin-web-master 的代码是为了实现上述功能而编写的,它通过与后端服务器进行交互,获取商城的数据,并将数据以友好的方式展示给管理员。同时,它还提供了各种操作界面,使管理员可以方便地对商城的各项运营进行管理。 总之,mall-admin-web-master 是一个商城后台管理系统的前端代码,通过它可以实现商城的后台管理功能,提升管理员的工作效率。 ### 回答3: mall-admin-web-master 是一个商场管理系统的前端项目,细分为商场管理系统的前端部分。该项目的主要功能是通过网页界面来实现商场的管理操作。具体来说,mall-admin-web-master 主要包括以下几个方面: 1. 登录注册模块:提供用户登录和注册功能,保证商场管理者可以安全地访问和操作系统。 2. 商场概述模块:展示商场的整体运营情况,包括当天的营业额、商品销售量等重要数据,帮助管理者了解商场的整体运营状况。 3. 商品管理模块:提供对商场内商品进行增删改查的功能,包括商品的添加、编辑、删除和查询等操作,方便管理者对商品进行全面的管理。 4. 订单管理模块:对商场内的订单进行管理,包括订单的查询、审核、发货等操作,帮助管理者实现对订单的有效管理,提高订单处理的效率。 5. 店铺管理模块:对商场内的店铺进行管理,包括店铺的添加、编辑、删除等操作,帮助管理者对店铺进行管理和布局。 6. 用户管理模块:对商场内的用户进行管理,包括用户的注册信息、下单记录、余额等进行管理,方便管理者对用户进行跟踪和统计。 总的来说,mall-admin-web-master 是一个功能丰富、操作简便的商场管理系统前端项目,能够帮助商场管理者有效地进行商场的管理和运营。其用户友好的界面设计和强大的功能模块,能够提高商场管理的效率和水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踢足球的程序员·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值