談springboot兩種實現結構

꧁ʚ星月天空ɞ꧂發表於2024-05-07

概述

最近由於入職華海智匯,所以文章也少了,並不是自己懈怠了,而是華海的保密措施不允許我上班寫文章了,更何況還有無盡的加班。。。。。。。。。唉,所幸現在習慣了好多,現在覺著該記錄一下知識了。目前市場上,要實現Java專案主要有Maven和Gradle兩種框架,其中Gradle是新興勢力,Maven是老牌勢力,其實我更加喜歡用Gradle,因為更加便捷,無奈,現在市面上Maven仍然是主流,因為穩定,更因為許多老專案都是Maven搭建的。。。。。。今天這篇文章主要是介紹兩種實現springboot的方式,以防以後忘記

第一種:Domain(entity)-Mapper-Service-Controller

這種方式是我的老師教給我的方式,我也認為是最簡單的方式,也是我的最愛,不過卻是不常見的
例如:

實體類層:Domain(entity)

package com.example.pmxt.domain;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
@TableName("sys_region")
public class Region {

    @NotNull(message = "id不能為空")
//    @NotBlank(message = "id不能為空")
//    @Length(min = 6,max = 6,message = "長度必須為6")
    @ExcelProperty("編號")
    private Integer id;

    @NotNull(message = "名稱不能為空")
    @NotBlank(message = "名稱不能為空")
    @ExcelProperty("名稱")
    private String name;

    @NotNull(message = "父類id不能為空")
//    @NotBlank(message = "父類id不能為空")
//    @Length(min = 6,max = 6,message = "長度必須為6")
    @ExcelProperty("父類id")
    private Integer parentId;

    @ExcelProperty("備註")
    private String remark;

}

這一層在兩種方式中並無區別,就是建立實體類,方便管理。

Mapper層

這一層主要有兩種實現方式:註解和寫<這種標籤,註解比較多,因為簡便,標籤的話,應該是老程式設計師專屬吧,註解如下:

package com.example.pmxt.modules.region;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.pmxt.domain.Region;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface RegionMapper extends BaseMapper<Region> {

//    @Select("SELECT sys_region.id,sys_region.name,sys_region.parent_id from sys_region,busi_bd.szd where sys_region.id = busi_bd.szd union SELECT sys_region.id,sys_region.name,sys_region.parent_id from sys_region,busi_bd where sys_region.id = concat(left(busi_bd.szd,4),'00') union SELECT sys_region.id,sys_region.name,sys_region.parent_id from sys_region,busi_bd where sys_region.id = concat(left(busi_bd.szd,2),'0000');")
//    List<Region> selectbybd();

    @Select("select * from sys_region where name = #{name}")
    Region getByname(String name);

    @Select("select parent_id from sys_region where name = #{name};")
    Integer getparentIdByName(String name);

    @Select("select id from sys_region where name = #{name};")
    Integer getIdByName(String name);

    @Select("select * from sys_region where concat(id) like concat(left(concat(#{id}),2),'%');")
    List<Region> getByProvince(Integer id);

    @Select("select * from sys_region where concat(id) like concat(left(concat(#{id}),4),'%');")
    List<Region> getByCity(Integer id);

    @Select("select * from sys_region where id = #{id}")
    List<Region> getByCounty(Integer id);


}

注意BaseMapper來自於Mybatis-plus導包

主要就是註解+SQL語句後,下面跟個方法名

Service層

這塊是兩種方式差別最大的一個,這種方式只需要一個Service類就好了,但是需要一個工具類BaseService。

BaseService:

package com.example.pmxt.common;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

public class BaseService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {
}

所有的Service都可以繼承這個BaseService,這樣就不用寫ServiceImpl了,只需要解除安裝Service中就行了

Service:

package com.example.pmxt.modules.region;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.example.pmxt.common.BaseService;
import com.example.pmxt.domain.Region;
import lombok.SneakyThrows;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@Service
@Transactional
public class RegionService extends BaseService<RegionMapper,Region> {

    private final RegionMapper mapper;

    @Autowired
    public RegionService(RegionMapper mapper) {
        this.mapper = mapper;
    }


    @SneakyThrows
    public boolean importFileToDB(boolean deleteHistory, MultipartFile file) {
    //是否刪除資料庫表中歷史資料
        if (deleteHistory) {
            this.remove(null);
        }
    //讀取excel表格中資料
        EasyExcel.read(file.getInputStream(), Region.class, new ReadListener<Region>() {
            //定義一個常量BATCH_SIZE與一個列表ls
            private static final int BATCH_SIZE = 1000;
            private List<Region> ls = Lists.newArrayList();
            //重寫invoke方法
            @Override
            public void invoke(Region data, AnalysisContext context) {
                //System.err.println(data);
                //列表裡新增Flowfee類的資料
                ls.add(data);
                //每1000條放到資料庫裡面
                if (ls.size() >= BATCH_SIZE) {
                    RegionService.this.saveBatch(ls);
                    ls.clear();
                }
            }
            //重寫doAfterAllAnalysed方法,處理剩下的資料,例如1050條,其中1000條在上面已經放到資料庫,剩下的50條下面處理
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                RegionService.this.saveBatch(ls);
            }
        }).sheet().doRead();
        return true;
    }

    public Integer getparentIdByName(String name){
        return mapper.getparentIdByName(name);
    }
    public Integer getIdByName(String name){
        return mapper.getIdByName(name);
    }

    public List<Region> gettable(String name){
        if (mapper.getByname(name)==null){
            return null;
        }
        Integer id = mapper.getIdByName(name);
        if ("0000".equals(String.valueOf(id).substring(2))){
            return mapper.getByProvince(id);
        }else if ("00".equals(String.valueOf(id).substring(4))){
            return mapper.getByCity(id);
        }else {
            return mapper.getByCounty(id);
        }
    }
}

Controller層

這一層是用於給前端寫介面的類,兩種方法基本一致

package com.example.pmxt.modules.region;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.example.pmxt.common.ReturnResult;
import com.example.pmxt.domain.Region;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@Validated
@RequestMapping("/regions")
public class RegionController {

    private final RegionService service;

    @Autowired
    public RegionController(RegionService service) {
        this.service = service;
    }

    @GetMapping()
    public ReturnResult getAllRegion(){
        //這裡用的MyBatis Plus
        List<Region> dtos = service.list();
        //配置
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定義屬性名 都要預設值的
        treeNodeConfig.setIdKey("id");
        // 最大遞迴深度
        treeNodeConfig.setDeep(4);
        //轉換器
        List<Tree<Integer>> treeNodes = TreeUtil.build(dtos, 0, treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getParentId());
                    tree.setName(treeNode.getName());
                });
        return ReturnResult.buildSuccessResult(treeNodes);
    }

    @GetMapping("/name")
    public ReturnResult getByName(@NotNull(message = "parentid不能為空") String name){
        Integer parentid = service.getparentIdByName(name);
        //這裡用的MyBatis Plus
        List<Region> dtos = service.gettable(name);
        if (dtos == null){
            return ReturnResult.buildFailureResult("該地區不存在");
        }
        //配置
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定義屬性名 都要預設值的
        treeNodeConfig.setIdKey("id");
        // 最大遞迴深度
        treeNodeConfig.setDeep(3);
        //轉換器
        List<Tree<Integer>> treeNodes = TreeUtil.build(dtos, parentid, treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getParentId());
                    tree.setName(treeNode.getName());
                });
        return ReturnResult.buildSuccessResult(treeNodes);

    }

//    @GetMapping("/selectbybd")
//    public ReturnResult selectbybd(){
//        return ReturnResult.buildSuccessResult(service.selectbybd());
//    }

    @PostMapping()
    public ReturnResult addRegion(@RequestBody @Validated Region region){
        if (region == null){
            return ReturnResult.buildFailureResult("行政區劃不能為空");
        }
            return ReturnResult.buildSuccessResult(service.save(region));

    }

    @DeleteMapping("/{id}")
    public ReturnResult deleteRegionById(@PathVariable @NotNull(message = "id不能為空") Integer id){
        if(id == null){
            return ReturnResult.buildFailureResult("id不能為空");
        }
        Region r = service.getById(id);
        if (r != null){
            return ReturnResult.buildSuccessResult(service.removeById(id));
        }else {
            return ReturnResult.buildFailureResult("id不存在");
        }
    }

    @PutMapping()
    public ReturnResult updateRegion(@RequestBody Region region){
        if (region == null){
            return ReturnResult.buildFailureResult("行政區劃不能為空");
        }
        Region r = service.getById(region.getId());
        if (r != null) {
            return ReturnResult.buildSuccessResult(service.updateById(region));
        }else {
            return ReturnResult.buildFailureResult("id不存在");
        }
    }


    //@PostMapping定義IP地址對映方法與位置,@ApiOperation是swagger測試註解
    @PostMapping("/uploadregion")
    public ReturnResult excelToDatabase( @RequestParam boolean deleteHistory,
                                         @RequestPart("file") MultipartFile file) {
        if(service.importFileToDB(deleteHistory, file)){
            return ReturnResult.buildSuccessResult("新增成功",null);
        }else {
            return ReturnResult.buildFailureResult("新增失敗",null);
        }
    }


    @DeleteMapping("deletes")
    public ReturnResult deleteregions(Integer [] ids){
        if (ids.length == 0){
            return ReturnResult.buildFailureResult("行政區劃不能為空");
        }else {
            return ReturnResult.buildSuccessResult(service.removeBatchByIds(Arrays.asList(ids)));
        }
    }
}

第二種:Domain(entity)-Mapper-Service-ServiceImpl-Controller

這種方法主要就差在Service層,其餘層可以參考上面

Service層

Service:

public interface UserSerivce extends IService<User> {
}

這種方法Service要先繼承IService工具類,實際上ServiceImpl已將包含了IService中的所有方法

ServiceImpl:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserSerivce {

}

這就需要多寫一個Impl類,實際上兩者原理一樣,第二種多了個ServiceImpl<UserMapper, User> 實現 UserSerivce介面,而UserSerivce介面又要繼承IService,比較麻煩,不喜歡。。。。。,但是無奈,這是主流,尤其大廠還有程式碼檢視,第一種會被認為不對,但我個人覺得能實現功能就是好方法,你認為呢?

最後說明這兩種方法應該在Maven和Gradle框架中都可以使用,至少Maven是都可以的,因為我試過了,,Gradle中我用過第一種,第二種還沒用過,不過既然原理一致,應該都可以使用;

這篇文章只當自己對喜愛方法的紀念吧。。。。

相關文章