springboot多级分类源码

简介: springboot多级分类源码

如何实现多级分类,方便维护,容易获取子分类、父级分类、某个子分类的顶级分类的所有子分类;

一、数据建表

 

DROP TABLE IF EXISTS `oa_classification`;
CREATE TABLE `oa_classification`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '分类名称',
  `parent_id` bigint(20) NULL DEFAULT 0 COMMENT '父分类id',
  `sort` int(11) NOT NULL DEFAULT 0 COMMENT '显示顺序',
  `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '分类状态(0正常 1停用)',
  `deth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '纵深',
  `deth_name` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '纵深名称',
  `deth_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '纵深ID',
  `create_by` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '项目分类表' ROW_FORMAT = Dynamic;
 
SET FOREIGN_KEY_CHECKS = 1;

二、maven主要依赖

<!-- Mysql驱动包 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>
 
<!--ORM-->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.5.1</version>
</dependency>
 
<!--hutool-->
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.8.0</version>
</dependency>

三、代码

1、controller

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
 
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
 
 
@Api(tags = "OA-系统设置-报销项目分类")
@RestController
@RequestMapping("/projectManagement")
@Validated
@Slf4j
public class ClassificationController extends BaseController {
 
    @Resource
    private OaClassificationService classificationService;
 
 
    @PostMapping("/classification/create")
    @ApiOperation("创建报销项目分类")
    public AjaxResult createClassification(@Valid @RequestBody ClassificationCreateReqVO reqVO) {
        Long classificationId = classificationService.createClassification(reqVO);
        return toAjax(true);
    }
 
    @PutMapping("update")
    @ApiOperation("更新报销项目分类")
    public AjaxResult updateClassification(@Valid @RequestBody ClassificationUpdateReqVO reqVO) {
        classificationService.updateClassification(reqVO);
        return toAjax(true);
    }
 
    @GetMapping("/get")
    @ApiOperation("获得报销项目分类信息")
    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
    public AjaxResult getClassification(@RequestParam("id") Long id) {
        OaClassification classification = classificationService.getClassification(id);
        return success(classification);
    }
 
    @DeleteMapping("delete")
    @ApiOperation("删除报销项目分类")
    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1", dataTypeClass = Long.class)
    public AjaxResult deleteClassification(@RequestParam("id") Long id) {
        classificationService.deleteClassification(id);
        return toAjax(true);
    }
 
 
    @GetMapping("/listChildren")
    @ApiOperation("获取报销项目分类列表-子分类")
    public AjaxResult listClassificationsChildren(ClassificationListReqVO reqVO) {
        List<OaClassification> list = classificationService.getSimpleClassifications(reqVO);
        //配置
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 都要默认值的
        // 排序字段,这个字段不能是null,不然会报错,默认最好是数字
        treeNodeConfig.setWeightKey("sort");
        treeNodeConfig.setIdKey("id");
        // 父级id字段
        treeNodeConfig.setParentIdKey("parentId");
        // 最大递归深度
        //treeNodeConfig.setDeep(3);
        //转换器
        List<Tree<Integer>> build = TreeUtil.build(list, 0, treeNodeConfig, ((object, treeNode) -> {
            treeNode.setId(object.getId().intValue());//id
            treeNode.setParentId(object.getParentId().intValue());//父id
            treeNode.putExtra("name", object.getName());
            treeNode.putExtra("sort", object.getSort());
            treeNode.putExtra("status", object.getStatus());
        }));
        log.info(JSON.toJSONString(build));
        return success(build);
    }
 
    @GetMapping("/list-all-simple-children")
    @ApiOperation(value = "获取报销项目分类精简信息列表-子分类", notes = "只包含被开启的报销项目分类,主要用于前端的下拉选项")
    public AjaxResult getSimpleClassificationsChildren() {
        List<Tree<Integer>> simpleClassificationsChildren = classificationService.getSimpleClassificationsChildren();
        return success(simpleClassificationsChildren);
    }
}

2、service

import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
 
/**
 *
 */
public interface OaClassificationService extends IService<OaClassification> {
    /**
     * 创建分类
     *
     * @param reqVO 分类信息
     * @return 分类编号
     */
    Long createClassification(ClassificationCreateReqVO reqVO);
 
    /**
     * 更新分类
     *
     * @param reqVO 分类信息
     */
    void updateClassification(ClassificationUpdateReqVO reqVO);
 
    /**
     * 删除分类
     *
     * @param id 分类编号
     */
    void deleteClassification(Long id);
 
    /**
     * 筛选分类列表
     *
     * @param reqVO 筛选条件请求 VO
     * @return 分类列表
     */
    List<OaClassification> getSimpleClassifications(ClassificationListReqVO reqVO);
 
    /**
     *获取项目分类精简信息列表-子分类
     * @return
     */
    List<Tree<Integer>> getSimpleClassificationsChildren();
 
    /**
     * 获得所有子分类,从缓存中
     *
     * @param parentId 分类编号
     * @param list 是否递归获取所有
     * @return 子分类列表
     */
    void getClassiByParentId( List<OaClassification> list,Long parentId);
 
 
    /**
     * 获得分类信息
     *
     * @param id 分类编号
     * @return 分类信息
     */
    OaClassification getClassification(Long id);
 
}
 
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
 
/**
 *
 */
@Service
public class OaClassificationServiceImpl extends ServiceImpl<OaClassificationMapper, OaClassification>
        implements OaClassificationService {
    String slash = "/";
    String comma = ",";
    @Resource
    private OaClassificationMapper classificationMapper;
 
 
    @Override
    public Long createClassification(ClassificationCreateReqVO reqVO) {
        // 校验正确性
        Long parentId = reqVO.getParentId();
        checkCreateOrUpdate(null, parentId, reqVO.getName());
        // 插入分类
        OaClassification classifiction = new OaClassification();
        BeanUtils.copyProperties(reqVO, classifiction);
        setLevelDept(parentId, classifiction);
        classificationMapper.insert(classifiction);
        Long id = classifiction.getId();
        if (Objects.equals(classifiction.getParentId(), 0L)) {
            OaClassification update = new OaClassification();
            update.setId(id);
            update.setDethId(String.valueOf(id));
            classificationMapper.updateById(update);
        } else {
            OaClassification parentClass = classificationMapper.selectById(classifiction.getParentId());
            OaClassification update = new OaClassification();
            update.setId(id);
            update.setDethId(parentClass.getDethId().concat(slash).concat(String.valueOf(id)));
            classificationMapper.updateById(update);
        }
        return id;
    }
 
 
    @Override
    public void updateClassification(ClassificationUpdateReqVO reqVO) {
        Long id = reqVO.getId();
        Long parentId = reqVO.getParentId();
        // 校验正确性
        checkCreateOrUpdate(id, parentId, reqVO.getName());
        // 更新分类
        OaClassification updateObj = new OaClassification();
        BeanUtils.copyProperties(reqVO, updateObj);
        setLevelDept(parentId, updateObj);
        classificationMapper.updateById(updateObj);
        if (!Objects.equals(parentId, 0L)) {
            OaClassification parentClass = classificationMapper.selectById(parentId);
            OaClassification update = new OaClassification();
            update.setId(id);
            update.setDethId(parentClass.getDethId().concat(slash).concat(String.valueOf(id)));
            classificationMapper.updateById(update);
        }
        //修改是修改子分类名称
        reName(updateObj.getId());
    }
 
    /**
     * @param parentId      父级ID
     * @param classifiction
     */
    private void setLevelDept(Long parentId, OaClassification classifiction) {
        //如果不是一级分类插入层级、纵深
        if (parentId == null || Objects.equals(parentId, 0L)) {
            //设置层级
 
            classifiction.setParentId(0L);
            classifiction.setDethName(classifiction.getName());
            return;
        } else {
            OaClassification dbOaClassification = classificationMapper.selectById(parentId);
 
            //设置纵深
            String deth = dbOaClassification.getDeth();
            if (StrUtil.isEmpty(deth)) {
                classifiction.setDeth(String.valueOf(parentId));
            } else {
                classifiction.setDeth(deth.concat(comma).concat(String.valueOf(parentId)));
            }
            classifiction.setDethName(dbOaClassification.getDethName().concat("/").concat(classifiction.getName()));
        }
    }
 
    @Async
    public void reName(Long id) {
        List<OaClassification> classificationDOs = classificationMapper.selectByParentId(id);
        if (classificationDOs == null) {
            return;
        }
        //遍历子类
        classificationDOs.forEach((tem) -> {
            Long parentId = tem.getParentId();
            OaClassification dbOaClassification = classificationMapper.selectById(parentId);
            //设置层级
 
            //设置纵深
            String deth = dbOaClassification.getDeth();
            if (StrUtil.isEmpty(deth)) {
                tem.setDeth(String.valueOf(parentId));
            } else {
                tem.setDeth(deth.concat(comma).concat(String.valueOf(parentId)));
            }
            tem.setDethName(dbOaClassification.getDethName().concat(slash).concat(tem.getName()));
            tem.setDethId(dbOaClassification.getDethId().concat(slash).concat(tem.getId().toString()));
            classificationMapper.updateById(tem);
            reName(tem.getId());
        });
    }
 
    @Override
    public void deleteClassification(Long id) {
        // 校验是否存在
        checkClassificationExists(id);
        // 校验是否有子分类
        List<OaClassification> oaClassifications = classificationMapper.selectByParentId(id);
        if (!CollUtil.isEmpty(oaClassifications)) {
            throw new ServiceException("存在子分类,无法删除");
        }
 
        classificationMapper.deleteById(id);
    }
 
    @Override
    public List<OaClassification> getSimpleClassifications(ClassificationListReqVO reqVO) {
        return classificationMapper.selectPageList(reqVO);
    }
 
    @Override
    public List<Tree<Integer>> getSimpleClassificationsChildren() {
        // 获得项目分类列表,只要开启状态的
        ClassificationListReqVO reqVO = new ClassificationListReqVO();
        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        List<OaClassification> list = getSimpleClassifications(reqVO);
 
        //配置
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 都要默认值的
        // 排序字段,这个字段不能是null,不然会报错,默认最好是数字
        treeNodeConfig.setWeightKey("sort");
        treeNodeConfig.setIdKey("id");
        // 父级id字段
        treeNodeConfig.setParentIdKey("parentId");
        // 最大递归深度
        //treeNodeConfig.setDeep(3);
        //转换器
        List<Tree<Integer>> trees = TreeUtil.build(list, 0, treeNodeConfig, ((object, treeNode) -> {
            treeNode.setId(object.getId().intValue());//id
            treeNode.setParentId(object.getParentId().intValue());//父id
            treeNode.putExtra("name", object.getName());
        }));
        return trees;
    }
 
    @Override
    public void getClassiByParentId(List<OaClassification> list, Long id) {
        if (id == null) {
            return;
        }
        List<OaClassification> classificationDOs = classificationMapper.selectByParentId(id);
        if (CollUtil.isEmpty(classificationDOs)) {
            return;
        }
        list.addAll(classificationDOs);
        // 递归,简单粗暴
        classificationDOs.forEach((tem) -> {
            this.getClassiByParentId(list, tem.getId());
        });
 
        return;
    }
 
 
    private void checkCreateOrUpdate(Long id, Long parentId, String name) {
        // 校验自己存在
        checkClassificationExists(id);
        // 校验父分类的有效性
        checkParentClassificationEnable(id, parentId);
        // 校验分类名的唯一性
        checkClassificationNameUnique(id, parentId, name);
    }
 
    private void checkParentClassificationEnable(Long id, Long parentId) {
        if (parentId == null || Objects.equals(parentId, 0L)) {
            return;
        }
        // 不能设置自己为父分类
        if (parentId.equals(id)) {
            throw new ServiceException("不能设置自己为父分类");
        }
        // 父不存在
        OaClassification classifiction = classificationMapper.selectById(parentId);
        if (classifiction == null) {
            throw new ServiceException("父级分类不存在");
        }
        // 父分类被禁用
        if (!CommonStatusEnum.ENABLE.getStatus().equals(classifiction.getStatus())) {
            throw new ServiceException("分类不处于开启状态,不允许选择");
        }
        // 父分类不能是原来的子分类
        List<OaClassification> children = new ArrayList<>();
        this.getClassiByParentId(children, id);
        if (children.stream().anyMatch(classifiction1 -> classifiction1.getId().equals(parentId))) {
            throw new ServiceException("不能设置自己的子分类为父分类");
        }
    }
 
    private void checkClassificationExists(Long id) {
        if (id == null) {
            return;
        }
        OaClassification classifiction = classificationMapper.selectById(id);
        if (classifiction == null) {
            throw new ServiceException("分类不存在");
        }
    }
 
 
    private void checkClassificationNameUnique(Long id, Long parentId, String name) {
        OaClassification menu = classificationMapper.selectByParentIdAndName(parentId, name);
        if (menu == null) {
            return;
        }
        // 如果 id 为空,说明不用比较是否为相同 id 的
        if (id == null) {
            throw new ServiceException("已经存在该名字的分类");
        }
        if (!menu.getId().equals(id)) {
            throw new ServiceException("已经存在该名字的分类");
        }
    }
 
 
    @Override
    public OaClassification getClassification(Long id) {
        return classificationMapper.selectById(id);
    }
 
 
}
 
 
 
 

3、mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 
import org.apache.ibatis.annotations.Param;
 
import java.util.List;
 
/**
 * @Entity generator.domain.OaClassification
 */
public interface OaClassificationMapper extends BaseMapper<OaClassification> {
 
    List<OaClassification> selectPageList(@Param("reqVO") ClassificationListReqVO reqVO);
 
 
    OaClassification selectByParentIdAndName(@Param("parentId") Long parentId, @Param("name") String name);
 
 
    List<OaClassification> selectByParentId(Long parentId);
 
 
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxxx.mapper.OaClassificationMapper">
 
    <resultMap id="BaseResultMap" type="com.xxxx.domain.OaClassification">
        <id property="id" column="id" jdbcType="BIGINT"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="parentId" column="parent_id" jdbcType="BIGINT"/>
        <result property="sort" column="sort" jdbcType="INTEGER"/>
        <result property="status" column="status" jdbcType="TINYINT"/>
        <result property="deth" column="deth" jdbcType="VARCHAR"/>
        <result property="dethName" column="deth_name" jdbcType="VARCHAR"/>
        <result property="dethId" column="deth_id" jdbcType="VARCHAR"/>
        <result property="createBy" column="create_by" jdbcType="VARCHAR"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
        <result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
        <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
    </resultMap>
 
    <sql id="Base_Column_List">
        id
        ,name,parent_id,
        sort,status,deth,
        deth_name,deth_id,create_by,
        create_time,update_by,update_time
    </sql>
    <select id="selectPageList" resultType="com.xxxx.domain.OaClassification">
        select * from oa_classification
        <where>
            <if test="reqVO.id != null ">
                id= #{reqVO.name}
            </if>
            <if test="reqVO.name != null and reqVO.name != ''">
                and name like (concat('%', #{reqVO.name}, '%'))
            </if>
            <if test="reqVO.status != null ">
               and status= #{reqVO.status}
            </if>
        </where>
        order by sort desc,id desc
    </select>
    <select id="selectByParentIdAndName" resultType="com.xxxx.domain.OaClassification">
        select * from oa_classification
        <where>
            <if test="parentId != null ">
                parent_id= #{parentId}
            </if>
            <if test="name != null and name != ''">
                and name =#{name}
            </if>
        </where>
    </select>
    <select id="selectByParentId" resultType="com.xxxx.domain.OaClassification">
        select * from oa_classification
        <where>
            <if test="parentId != null ">
                parent_id= #{parentId}
            </if>
        </where>
    </select>
 
 
</mapper>

4、基础类

1.@Data
@TableName(value = "oa_classification", autoResultMap = true)
@EqualsAndHashCode(callSuper = true)
public class OaClassification extends BaseEntityTwo {
 
    /**
    * 分类id
    */
    @ApiModelProperty("分类id")
    private Long id;
    /**
    * 分类名称
    */
    @ApiModelProperty("分类名称")
    //@Length(max= 100,message="编码长度不能超过100")
    private String name;
    /**
    * 父分类id
    */
    @ApiModelProperty("父分类id")
    private Long parentId;
    /**
    * 显示顺序
    */
    @ApiModelProperty("显示顺序")
    private Integer sort;
    /**
    * 分类状态(0正常 1停用)
    */
    @ApiModelProperty("分类状态(0正常 1停用)")
    private Integer status;
    /**
    * 纵深
    */
    @ApiModelProperty("纵深")
    //@Length(max= 255,message="编码长度不能超过255")
    private String deth;
    /**
    * 纵深名称
    */
    @ApiModelProperty("纵深名称")
    //@Length(max= 300,message="编码长度不能超过300")
    private String dethName;
    /**
    * 纵深ID
    */
    @ApiModelProperty("纵深ID")
    //@Length(max= 255,message="编码长度不能超过255")
    private String dethId;
 
}
 
@Data
public class BaseEntityTwo implements Serializable {
    private static final long serialVersionUID = 1L;
 
 
    /**
     * 创建者
     */
    @TableField(fill = FieldFill.INSERT)
    @Excel(name = "创建者",sort = 101)
    private String createBy;
 
    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    @Excel(name = "创建时间", sort = 102,width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
    private Date createTime;
 
    /**
     * 更新者
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @Excel(name = "更新者",sort = 103)
    private String updateBy;
 
    /**
     * 更新时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @Excel(name = "更新时间", sort = 104,width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
    private Date updateTime;
 
}
@Data
public class ClassificationBaseVO {
 
    @ApiModelProperty(value = "分类名称", required = true, example = "xxx")
    @NotBlank(message = "分类名称不能为空")
    @Size(max = 30, message = "分类名称长度不能超过30个字符")
    private String name;
 
    @ApiModelProperty(value = "父菜单ID,一级分类", example = "1024")
    private Long parentId;
 
    private Integer sort;
 
 
}
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ClassificationCreateReqVO extends ClassificationBaseVO {
}
@Data
public class ClassificationListReqVO {
 
    @ApiModelProperty(value = "分类名称", example = "王二", notes = "模糊匹配")
    private String name;
 
    @ApiModelProperty(value = "分类ID", example = "1")
    private Long id;
 
    @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
    private Integer status;
 
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ClassificationSimpleRespVO {
 
    @ApiModelProperty(value = "分类编号", required = true, example = "1024")
    private Long id;
 
    @ApiModelProperty(value = "分类名称", required = true, example = "王二")
    private String name;
 
    @ApiModelProperty(value = "父分类 ID", required = true, example = "1024")
    private Long parentId;
 
}
@Data
@EqualsAndHashCode(callSuper = true)
public class ClassificationUpdateReqVO extends ClassificationBaseVO {
 
    @ApiModelProperty(value = "分类编号", required = true, example = "1024")
    @NotNull(message = "分类编号不能为空")
    private Long id;
 
    @ApiModelProperty(value = "状态 0开启 1关闭", required = true, example = "1")
    @NotNull(message = "状态不能为空")
    private Integer status;
 
}

四、不足

1、纵深名称和纵深ID使用分隔符+字符存储。可以使用json存储,配合mybatis的typeHandler属性,方便业务使用时结构化;

2、可以增加缓存提升获取分类的效率,如果项目分类比较多,不建议一次取出;

相关文章
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
2月前
|
前端开发 Java
表白墙/留言墙 —— 初级SpringBoot项目,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
文章通过一个表白墙/留言墙的初级SpringBoot项目实例,详细讲解了如何进行前后端开发,包括定义前后端交互接口、创建SpringBoot项目、编写前端页面、后端代码逻辑及实体类封装的全过程。
104 3
表白墙/留言墙 —— 初级SpringBoot项目,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
2月前
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
393 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
1天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
11天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
69 13
|
19天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
2月前
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
209 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
3月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
494 37
|
3月前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)