Spring Boot + MyBatis 实现站位标记系统实战

项目背景

本系统主要用于地图站位小程序,通过地图站位展示贷款相关的地理位置信息,支持按不同条件筛选和统计,帮助业务人员更好地进行贷后管理。

核心功能分析

1. 功能架构

系统支持以下核心功能:

  • 地图标记点展示(客户、担保人、抵押物)
  • 表内外数据区分
  • 距离范围筛选
  • 多维度条件查询
  • 贷款状态统计

2. Controller层实现

复制代码
@RestController
@RequestMapping("/bank/app/mapwork")
public class AppMapworkController {

    @Autowired
    private AppMapworkService appMapworkService;

    @GetMapping("/index")
    @Operation(summary = "首页")
    public CommonResult<?> getIndex(AppMapworkReqVO req) {
        Map<String, Object> data = new HashMap<>();
        data.put("normal",0);
        data.put("overdue",0);
        data.put("lawsuit",0);
        List<AppMapworkRespVO> result = new ArrayList<>();
        
        // IO标志处理逻辑
        boolean inFlag = false;
        boolean outFlag = false;
        if(StringUtils.isEmpty(req.getIoFlag())){
            inFlag = true;
            outFlag = true;
        }else{
            if("in".equals(req.getIoFlag())){
                inFlag = true;
            }else if("out".equals(req.getIoFlag())){
                outFlag = true;
            }else if("all".equals(req.getIoFlag())){
                inFlag = true;
                outFlag = true;
            }
        }

        // 表内数据查询
        if(inFlag){
            if(StringUtils.isEmpty(req.getOther())){
                // 查询全部类型
                List<AppMapworkRespVO> custList = appMapworkService.getCustomerInMark(req);
                List<AppMapworkRespVO> guarantorList = appMapworkService.getGuarantorInMark(req);
                List<AppMapworkRespVO> mortgageList = appMapworkService.getMortgageInMark(req);
                result.addAll(custList);
                result.addAll(guarantorList);
                result.addAll(mortgageList);
            }else{
                // 按类型查询
                if("cust".equals(req.getOther())){
                    // 客户查询,特殊处理地址标记点
                    List<AppMapworkRespVO> custList = appMapworkService.getCustomerInMark(req);
                    if(UxUtil.isListNotEmpty(custList) && custList.size() == 1){
                        AppMapworkRespVO cust = custList.get(0);
                        List<AppMapworkRespVO> addressList = appMapworkService.getCustomerInAddressMark(req,cust.getMarkId());
                        if(UxUtil.isListNotEmpty(addressList)){
                            for(AppMapworkRespVO c : addressList){
                                c.setLoanId(cust.getLoanId());
                                c.setCustName(cust.getCustName());
                                c.setContractCode(cust.getContractCode());
                                c.setAmount(cust.getAmount());
                            }
                            result.addAll(addressList);
                        }
                    }
                    result.addAll(custList);
                }
                // ... 其他类型处理
            }
        }

        // 表外数据查询(逻辑类似)
        if(outFlag){
            // ... 同表内处理逻辑
        }
        
        data.put("marks",result);
        data.put("total",result.size());

        // 贷款状态统计
        if(StringUtils.isNotEmpty(req.getOther()) && "cust".equals(req.getOther()) && UxUtil.isListNotEmpty(result)){
            Long normalCount = result.stream().filter(o -> (o.getOverdueFlag() == 0 && o.getLawsuitFlag() == 0)).count();
            Long overdueCount = result.stream().filter(o -> (o.getOverdueFlag() == 1 && o.getLawsuitFlag() == 0)).count();
            Long lawsuitCount = result.stream().filter(o -> (o.getLawsuitFlag() == 1)).count();
            data.put("normal",normalCount);
            data.put("overdue",overdueCount);
            data.put("lawsuit",lawsuitCount);
        }

        return success(data);
    }
}

Service层设计

复制代码
@Service
@Validated
public class AppMapworkServiceImpl implements AppMapworkService {

    @Autowired
    private MapworkMapper mapworkMapper;

    @Override
    public List<AppMapworkRespVO> getCustomerInMark(AppMapworkReqVO req) {
        LambdaQueryWrapper<LoanInDO> queryWrapper = new LambdaQueryWrapper<>();
        
        // 模糊查询支持(客户名/代码/合同号)
        if(StringUtils.isNotEmpty(req.getCustName())){
            queryWrapper.apply(" (m.cust_name like {0} or m.cust_code like {1} or m.contract_code like {2} )",
                    UxUtil.likeForSql(req.getCustName()),UxUtil.likeForSql(req.getCustName()),UxUtil.likeForSql(req.getCustName()));
        }
        
        // 状态筛选
        if(StringUtils.isNotEmpty(req.getStatus())){
            if("normal".equals(req.getStatus())){
                queryWrapper.apply(" (m.overdue_flag = {0} and m.lawsuit_flag = {1})", 0,0);
            }else if("overdue".equals(req.getStatus())){
                queryWrapper.apply(" (m.overdue_flag = {0} and m.lawsuit_flag = {1}) ", 1,0);
            }else if("lawsuit".equals(req.getStatus())){
                queryWrapper.apply(" m.lawsuit_flag = {0} ", 1);
            }
        }
        
        return mapworkMapper.getCustomerInMark(req,queryWrapper);
    }
    
    // 其他方法实现类似...
}

Mapper层核心技术

1. 站位计算

MapworkMapper.java

复制代码
public interface MapworkMapper {

    List<AppMapworkRespVO> getCustomerInMark(@Param("req") AppMapworkReqVO req, @Param("ew") LambdaQueryWrapper<LoanInDO> queryWrapper);

...
}

MapworkMapper.xml

复制代码
<select id="getCustomerInMark" resultType="com.mxx.module.bank.controller.admin.app.vo.AppMapworkRespVO">
    SELECT
        cu.id * 10 + 1 as id,
        cu.id as mark_id,
        'ux_customer_in' as mark_type,
        cu.latitude as lat,
        cu.longitude as lng,
        m.overdue_flag,
        m.lawsuit_flag,
        1 as in_out_flag,
        m.id as loan_id,
        m.cust_code,
        m.cust_name,
        m.cust_id,
        m.contract_code,
        m.amount,
        cu.contact_way,
        cu.detail_address as address,
        <!-- 核心距离计算公式 -->
        ROUND(111.111 * sqrt(pow(cu.latitude - #{req.latitude}, 2) + 
             pow(cos(radians(#{req.latitude})) * (cu.longitude - #{req.longitude}),2)), 2) AS distance
    FROM
        ux_loan_in m
    LEFT JOIN ux_customer_in cu ON cu.id = m.cust_id
    WHERE 1 = 1
    <if test="ew != null">
        <if test="ew.sqlSegment != null">
            <if test="ew.sqlSegment != ''">
                AND ${ew.sqlSegment}
            </if>
        </if>
    </if>
    AND m.deleted = 0
    AND cu.deleted = 0
    AND cu.latitude is not null
    AND cu.longitude is not null
    HAVING #{req.radius} > distance
</select>

2. 唯一ID生成策略

复制代码
-- 不同类型标记点的唯一ID生成,避免ID冲突
cu.id * 10 + 1 as id,  -- 客户表内
cu.id * 10 + 2 as id,  -- 客户表外
cu.id * 10 + 3 as id,  -- 担保人表内
cu.id * 10 + 4 as id,  -- 担保人表外

技术亮点解析

1. 灵活的查询策略

系统支持多种组合查询:

  • ioFlag: in/out/all(表内/表外/全部)
  • other: cust/guarant/mortgage/all(客户/担保人/抵押物/全部)
  • status: normal/overdue/lawsuit(正常/逾期/诉讼)

2. 地理位置计算优化

复制代码
-- 基于经纬度的距离计算,考虑地球曲率
ROUND(111.111 * sqrt(pow(cu.latitude - #{req.latitude}, 2) + 
     pow(cos(radians(#{req.latitude})) * (cu.longitude - #{req.longitude}),2)), 2) AS distance

3. 数据聚合设计

复制代码
// 多种业务类型统一返回VO
List<AppMapworkRespVO> result = new ArrayList<>();
result.addAll(custList);      // 客户
result.addAll(guarantorList); // 担保人
result.addAll(mortgageList);  // 抵押物

总结

本文介绍的银行贷款地理位置标记系统具有以下优势:

  1. 架构清晰:Controller-Service-Mapper三层架构
  2. 扩展性强:易于添加新的标记点类型
  3. 性能优化:地理位置计算和查询优化
  4. 用户体验:丰富的筛选和统计功能

这套解决方案在实际项目中表现良好,为银行的贷后管理提供了有力的技术支撑。

相关推荐
老华带你飞2 小时前
水果购物网站|基于java+vue的水果购物网站系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·水果购物网站系统
失因2 小时前
HAProxy 与 Tomcat
java·运维·tomcat
泊风9362 小时前
深入C语言底层系列28-埃拉托斯特尼筛法
c语言·开发语言·算法
JH30732 小时前
深入解析Tomcat类加载器:为何及如何打破Java双亲委派模型
java·开发语言·tomcat
bug攻城狮2 小时前
Tomcat 9+ 版本默认主页迁移至 webapps.dist
java·tomcat
爱吃煎蛋的小新2 小时前
C#语法回忆零散巩固(持续更新最新版)
java·开发语言·笔记·学习·算法·c#
依加依等于绫2 小时前
javaweb tomcat的使用
java·tomcat
一只乔哇噻2 小时前
java后端工程师进修ing(研一版‖day48)
java·开发语言·学习
x-ming-code2 小时前
Spring AOP + Redisson 实现基于注解的分布式限流方案
java·redis·分布式·spring