项目架构优化之路-------持续更新

简介: 前言:对于一个项目的优化,主要分为两种,一种是设计优化,一种是性能优化性能优化主要是值对代码执行效率的优化,比如缓存优化,算法优化等都属于性能优化,而设计优化则是值对代码逻辑以及代码结构的精简和代码可读性的优化。

案例:(设计优化,项目基于SSH框架,并且使用spring-data-jpa)

这里以一个基于ssh框架的项目为例,相信大家都知道,我们在使用ssh框架完成一个项目的时候,通常会为每一

个实体类的对象创建一个对应的action,创建项目目录如下:

微信图片_20221110171000.png

我们现在要做的就是对action中公共的部分进行抽取,对代码结构进行精简,首先我们看其中两个未抽取action

的代码结构:

@Controller
@Scope("prototype")
@ParentPackage("json-default")
@Namespace("/")
public class CourierAction extends ActionSupport implements ModelDriven<Courier> {
  // 模型驱动接收收派员信息
  private Courier courier = new Courier();
  @Override
  public Courier getModel() {
    return courier;
  }
  // 属性驱动接收分页信息
  private int page; // 要显示的页码数
  private int rows; // 每个页面上要显示的数据的条数
  public void setPage(int page) {
    this.page = page;
  }
  public void setRows(int rows) {
    this.rows = rows;
  }
  // 接收作废送派员或者还原收派员时用户选中的送派员的id
  private String ids;
  // 接收状态标记
  private String status;
  public void setStatus(String status) {
    this.status = status;
  }
  public void setIds(String ids) {
    this.ids = ids;
  }
  @Autowired
  private ICourierService CourierServiceImpl;
  @Action(value = "courier_save", results = {
      @Result(name = "success", type = "redirect", location = "/pages/base/courier.html") })
  public String save() {
    CourierServiceImpl.save(courier);
    return SUCCESS;
  }
  @Action(value = "courier_pageQuery", results = { @Result(name = "success", type = "json") })
  public String pageQuery() {
    // 封装数据
    Pageable pageable = new PageRequest(page - 1, rows, Direction.ASC, "courierNum");
    // 调用方法查询到封装好的页面数据
    Page<Courier> page = CourierServiceImpl.pageQuery(new Specification<Courier>() {
      @Override
      public Predicate toPredicate(Root<Courier> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<>();
        // 对接收到的数据进行判断,只要不为空的时候才是查询条件
        if (!StringUtils.isBlank(courier.getCourierNum())) { // 对工号进行判断
          Predicate p1 = cb.equal(root.get("courierNum").as(String.class), courier.getCourierNum());
          predicates.add(p1);
        }
        if (StringUtils.isNotBlank(courier.getCompany())) { // 对所属的单位进行判断
          Predicate p2 = cb.like(root.get("company").as(String.class), "%" + courier.getCompany() + "%");
          predicates.add(p2);
        }
        if (!StringUtils.isBlank(courier.getType())) { // 对类型进行判断
          Predicate p3 = cb.equal(root.get("type").as(String.class), courier.getType());
          predicates.add(p3);
        }
        // 对收派标准进行判断,涉及到了多表查询
        Join<Object, Object> join = root.join("standard", JoinType.INNER);
        if (courier.getStandard() != null && StringUtils.isNotBlank(courier.getStandard().getName())) {
          Predicate p4 = cb.equal(join.get("name").as(String.class), courier.getStandard().getName());
          predicates.add(p4);
        }
        return cb.and(predicates.toArray(new Predicate[0]));
      }
    }, pageable);
    // 获取数据
    long total = page.getTotalElements(); // 信息总条数
    List<Courier> rows = page.getContent(); // 所有的收派员对象
    // 将数据封装到一个map中
    Map<String, Object> result = new HashMap<String, Object>();
    result.put("total", total);
    result.put("rows", rows);
    // 将map集合压入到值栈中
    ActionContext.getContext().getValueStack().push(result);
    return SUCCESS;
  }
  /**
   * 一个作废或者还原派送员的方法
   * 
   * @return
   */
  @Action(value = "courier_updateBatch", results = {
      @Result(name = "success", location = "pages/base/courier.html", type = "redirect") })
  public String updateBatch() {
    Character deltag = status.charAt(0);
    String[] strIds = ids.split(",");
    // 调用业务层,实现批量作废或者还原
    CourierServiceImpl.delBatch(strIds, deltag);
    return SUCCESS;
  }
}
@Controller
@Scope("prototype")
@ParentPackage("json-default")
@Namespace("/")
public class StandardAction extends ActionSupport implements ModelDriven<Standard> {
  private int page; // 显示的页码
  private int rows; // 每页显示的条数
  public void setPage(int page) {
    this.page = page;
  }
  public void setRows(int rows) {
    this.rows = rows;
  }
  private Standard standard = new Standard();
  @Override
  public Standard getModel() {
    return standard;
  }
  @Autowired
  private IStandardService standardServiceImpl;
  /**
   * 添加收派标准的方法
   * 
   * @return
   */
  @Action(value = "standard_save", results = {
      @Result(name = "success", location = "/pages/base/standard.html", type = "redirect") })
  public String save() {
    standardServiceImpl.addStandard(standard);
    return SUCCESS;
  }
  /**
   * 一个分页查询的方法
   * 
   * @return
   */
  @Action(value = "standard_pageQuery", results = { @Result(name = "success", type = "json") })
  public String pageQuery() {
    // 封装分页查询数据到Pageable对象中
    Pageable pageRequest = new PageRequest(page - 1, rows, Direction.ASC, "minWeight");
    // 调用方法查询到封装好的页面
    Page<Standard> page = standardServiceImpl.pageQuery(pageRequest);
    int total = (int) page.getTotalElements(); // 数据总条数
    List<Standard> standards = page.getContent(); // 查询到的页面的所有信息
    // 将数据封装到map集合并压入值栈顶部,利用框架特性将其转换成json数据返回到服务器
    Map<String, Object> result = new HashMap<>();
    result.put("total", total);
    result.put("rows", standards);
    ActionContext.getContext().getValueStack().push(result);
    return SUCCESS;
  }
  @Action(value = "standard_findAll", results = { @Result(name = "success", type = "json") })
  public String findAll() {
    // 调用方法查询到所有数据
    List<Standard> standards = standardServiceImpl.findAll();
    // 将数据封装到map集合并压入值栈顶部,利用框架特性将其转换成json数据返回到服务器
    ActionContext.getContext().getValueStack().push(standards);
    return SUCCESS;
  }
}

对于以上代码我们发现,首先,每个action都继承了ActionSupport类,都采用了模型驱动去接收封装好的数


据,其次每个action都采用了属性驱动去接收分页的数据,最后每个action都继承了json-default包,这就导致

了在给服务器返回数据时,都有将数据压入到值栈顶部的操作。

分析后,我们都这部分代码进行优化,抽取baseAction,代码如下:

public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
  // 模型驱动
  protected T model;
  @Override
  public T getModel() {
    return model;
  }
  // 构造器 完成model实例化
  public BaseAction() {
    /**
     * 当子类实例化的时候,一定会先执行父类的构造函数,
     * 父类构造函数执行的时候,通过this调用子类对象,获取子类的字节码文件对象,
     * 再通过这个字节码对象获取继承父类型的泛型字节码对象, 
     * 通过这个字节码对象获取泛型参数,获取泛型参数的对应字节码对象
     * 通过这个字节码对象创建泛型对应对象
     */
    ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
    Class<T> clazz = (Class<T>) type.getActualTypeArguments()[0];
    try {
      model = clazz.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println("模型对象创建失败!");
    }
  }
  // 接收到分页的参数
  protected int page;
  protected int rows;
  public void setPage(int page) {
    this.page = page;
  }
  public void setRows(int rows) {
    this.rows = rows;
  }
  /**
   *  一个将分页数据压入到值栈顶部的方法
   * @param pagedata 页面数据
   */
  protected void pushPageDataToValueStack(Page<T> pagedata){
    long total = pagedata.getTotalElements();  // 数据条数
    List<T> content = pagedata.getContent();   // 页面数据 
    // 创建集合存储数据
    Map<String, Object> result = new HashMap<>();
    result.put("total",total);
    result.put("rows", content);
    // 数据存入值栈
    ActionContext.getContext().getValueStack().push(result);
  }
}

这部分代码相对而言比较复杂的就是就是怎么实例化泛型对象那一段了,我已经写了注释,这里不再多说

对于这种抽取base的思想其实很常见,除了baseAction,我们还可以抽取baseDao,这样让代码做到最大程度

的精简,提高代码的复用性,也能提高我们开发的效率,今天先写到这里,有时间继续更新,有什么不对的希望


相关文章
|
8月前
|
算法 物联网 定位技术
蓝牙室内定位技术解决方案:核心技术架构与优化实践
本文探讨了蓝牙iBeacon与Lora结合的室内定位技术,分析其在复杂室内环境中的优势与挑战。通过三层架构实现高精度定位,并提出硬件、算法与部署优化方向,助力智慧仓储、医疗等场景智能化升级。
419 0
蓝牙室内定位技术解决方案:核心技术架构与优化实践
|
8月前
|
消息中间件 监控 前端开发
如何开发项目管理系统中的项目结项板块?(附架构图+流程图+代码参考)
在企业项目管理中,“项目结项”是关键环节,常因流程不清、文档不全、审批滞后等问题导致交付困难。本文介绍如何通过“项目结项”模块实现线上化管理,涵盖结项申请、审批流程、成果上传、权限控制等功能,帮助团队高效完成项目收尾,避免成果丢失与流程混乱。内容包括功能设计、业务流程、系统架构、数据库设计、核心代码实现、前端交互及优化建议,助力项目管理系统快速落地并稳定运行。
|
5月前
|
机器学习/深度学习 数据可视化 网络架构
PINN训练新思路:把初始条件和边界约束嵌入网络架构,解决多目标优化难题
PINNs训练难因多目标优化易失衡。通过设计硬约束网络架构,将初始与边界条件内嵌于模型输出,可自动满足约束,仅需优化方程残差,简化训练过程,提升稳定性与精度,适用于气候、生物医学等高要求仿真场景。
580 4
PINN训练新思路:把初始条件和边界约束嵌入网络架构,解决多目标优化难题
|
5月前
|
运维 Prometheus 监控
别再“亡羊补牢”了!——聊聊如何优化企业的IT运维监控架构
别再“亡羊补牢”了!——聊聊如何优化企业的IT运维监控架构
220 8
|
5月前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
|
7月前
|
机器学习/深度学习 存储 人工智能
RAG系统文本检索优化:Cross-Encoder与Bi-Encoder架构技术对比与选择指南
本文将深入分析这两种编码架构的技术原理、数学基础、实现流程以及各自的优势与局限性,并探讨混合架构的应用策略。
497 10
RAG系统文本检索优化:Cross-Encoder与Bi-Encoder架构技术对比与选择指南
|
7月前
|
人工智能 自然语言处理 JavaScript
Github又一AI黑科技项目,打造全栈架构,只需一个统一框架?
Motia 是一款现代化后端框架,融合 API 接口、后台任务、事件系统与 AI Agent,支持 JavaScript、TypeScript、Python 多语言协同开发。它提供可视化 Workbench、自动观测追踪、零配置部署等功能,帮助开发者高效构建事件驱动的工作流,显著降低部署与运维成本,提升 AI 项目落地效率。
628 0
|
7月前
|
机器学习/深度学习 人工智能 算法
|
7月前
|
数据采集 机器学习/深度学习 运维
从数据感知到决策优化:MyEMS 开源能源管理系统的技术架构与实践效能解析
MyEMS 是一款开源能源管理系统,采用分层解耦与模块化设计,支持多能源协同监测与智能优化调度。系统具备数据采集、分析、预警、碳核算等功能,助力企业实现节能降耗、安全管控与低碳转型,已在百余家全球企业落地应用,具备自主可控、成本低、安全性强等优势,面向虚拟电厂、数字孪生等未来场景持续演进。
344 0
|
8月前
|
存储 Java 数据库连接
简单学Spring Boot | 博客项目的三层架构重构
本案例通过采用三层架构(数据访问层、业务逻辑层、表现层)重构项目,解决了集中式开发导致的代码臃肿问题。各层职责清晰,结合依赖注入实现解耦,提升了系统的可维护性、可测试性和可扩展性,为后续接入真实数据库奠定基础。
611 0

热门文章

最新文章