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

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

案例:(设计优化,项目基于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,这样让代码做到最大程度

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


相关文章
|
2月前
|
前端开发 JavaScript 测试技术
Kotlin教程笔记 - 适合构建中大型项目的架构模式全面对比
Kotlin教程笔记 - 适合构建中大型项目的架构模式全面对比
39 3
|
29天前
|
弹性计算 运维 监控
阿里云云服务诊断工具:合作伙伴架构师的深度洞察与优化建议
作为阿里云的合作伙伴架构师,我深入体验了其云服务诊断工具,该工具通过实时监控与历史趋势分析,自动化检查并提供详细的诊断报告,极大提升了运维效率和系统稳定性,特别在处理ECS实例资源不可用等问题时表现突出。此外,它支持预防性维护,帮助识别潜在问题,减少业务中断。尽管如此,仍建议增强诊断效能、扩大云产品覆盖范围、提供自定义诊断选项、加强教育与培训资源、集成第三方工具,以进一步提升用户体验。
675 243
|
22天前
|
机器学习/深度学习 算法 数据可视化
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
本文探讨了在量化交易中结合时序特征和静态特征的混合建模方法。通过整合堆叠稀疏降噪自编码器(SSDA)和基于LSTM的自编码器(LSTM-AE),构建了一个能够全面捕捉市场动态特性的交易系统。SSDA通过降噪技术提取股票数据的鲁棒表示,LSTM-AE则专注于捕捉市场的时序依赖关系。系统采用A2C算法进行强化学习,通过多维度的奖励计算机制,实现了在可接受的风险水平下最大化收益的目标。实验结果显示,该系统在不同波动特征的股票上表现出差异化的适应能力,特别是在存在明确市场趋势的情况下,决策准确性较高。
59 5
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
|
1天前
|
消息中间件 监控 小程序
电竞陪玩系统架构优化设计,陪玩app如何提升系统稳定性,陪玩小程序平台的测试与监控
电竞陪玩系统架构涵盖前端(React/Vue)、后端(Spring Boot/php)、数据库(MySQL/MongoDB)、实时通信(WebSocket)及其他组件(Redis、RabbitMQ、Nginx)。通过模块化设计、微服务架构和云计算技术优化,提升系统性能与可靠性。同时,加强全面测试、实时监控及故障管理,确保系统稳定运行。
|
7天前
|
存储 弹性计算 架构师
老板点赞!技术人如何用架构优化打赢降本增效战?
大家好,我是小米,一个喜欢分享技术的小架构师。通过亲身经历,我将介绍如何通过架构优化帮助公司降本增效。两年前,我加入一家初创公司,面对成本高企的问题,通过弹性伸缩、微服务化和数据治理等手段,成功降低了40%的技术成本,提升了60%的系统响应速度。希望我的经验能给你启发!关注我的微信公众号“软件求生”,获取更多技术干货。
17 5
|
1月前
|
存储 机器学习/深度学习 人工智能
【AI系统】计算图优化架构
本文介绍了推理引擎转换中的图优化模块,涵盖算子融合、布局转换、算子替换及内存优化等技术,旨在提升模型推理效率。计算图优化技术通过减少计算冗余、提高计算效率和减少内存占用,显著改善模型在资源受限设备上的运行表现。文中详细探讨了离线优化模块面临的挑战及解决方案,包括结构冗余、精度冗余、算法冗余和读写冗余的处理方法。此外,文章还介绍了ONNX Runtime的图优化机制及其在实际应用中的实现,展示了如何通过图优化提高模型推理性能的具体示例。
57 4
【AI系统】计算图优化架构
|
2月前
|
监控 前端开发 数据可视化
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
@icraft/player-react 是 iCraft Editor 推出的 React 组件库,旨在简化3D数字孪生场景的前端集成。它支持零配置快速接入、自定义插件、丰富的事件和方法、动画控制及实时数据接入,帮助开发者轻松实现3D场景与React项目的无缝融合。
207 8
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
|
23天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
76 3
|
2月前
|
监控 Serverless 云计算
探索Serverless架构:开发实践与优化策略
本文深入探讨了Serverless架构的核心概念、开发实践及优化策略。Serverless让开发者无需管理服务器即可运行代码,具有成本效益、高可扩展性和提升开发效率等优势。文章还详细介绍了函数设计、安全性、监控及性能和成本优化的最佳实践。
|
2月前
|
弹性计算 运维 开发者
后端架构优化:微服务与容器化的协同进化
在现代软件开发中,后端架构的优化是提高系统性能和可维护性的关键。本文探讨了微服务架构与容器化技术如何相辅相成,共同推动后端系统的高效运行。通过分析两者的优势和挑战,我们提出了一系列最佳实践策略,旨在帮助开发者构建更加灵活、可扩展的后端服务。