【SpringBoot】还不会SpringBoot项目模块分层?来这手把手教你

SpringBoot项目拆分 (spring多项目包扫描、依赖注入、jar包引入、数据库操作、项目启动、接口访问) SpringBoot项目拆分(按模块拆分) 在了解SpringBoot项目拆分之前首先我们需要了解微服务架构 什么是微服务? 单个轻量级服务一般为一个单独微服务,微服务讲究的是 专注某个功能的实现,比如登录系统只专注于用户登录方面功能的实现,讲究的是职责单一,开箱即用,可以独立运行。微服务架构系统是一个分布式的系统,按照业务进行划分服务单元模块,解决单个系统的不足,满足越来越复杂的业务需求。 马丁福勒(Martin Fowler):就目前而言,对于微服务业界并没有一个统一的、标准的定义。但通常而言,微服务 阅读详情
AI摘要

本文手把手教你如何创建一个模块化的SpringBoot项目,包括依赖层、主启动层、模块层的构建,以及分层结构如DAO、Service、Controller等的设置,同时讲解了如何配置多环境和日志管理。

前言

🍊缘由

经常看到网上很多优秀的开源项目中,代码简洁,模块分层完美。反观自己代码层级混乱,,却不知如何整理分层。此文手把手教你一步一步创建模块,左手右手一个慢动作。结合本人实际开发及个人项目中分层思路的分享,大神请勿喷。

⏲️本文阅读时长

约25分钟

🎯主要目标

  1. 熟练掌握SpringBoot项目分层思路,丝滑拆分模块

  1. 熟悉代码层级依赖,规范化管理模块分布

  1. 手把手实战学习,理论实践相结合

👨‍🎓试用人群

  1. 对于Springboot熟悉但是不知道合理分层小白

  1. 有自己分层思路可以互相分享学习

🍩水图

下图反面教材,传统单体应用,结构臃肿
下图分层截选自本人的一个小项目,模块清晰,分工明确
我们要实现的小栗子的分层

正文

🥫1.IDEA新建项目

起名第一步,一个好名字,说不定是个好的开始

假如我们的项目是个聊天相关的项目,英文对应chat,所以定义项目名为chat-boot,其他的以此效仿

点击New->project
选择 Maven项目,并选择 合适JDK版本,点击Next
录入项目名称,并填写GAV坐标,点击Finish
删除无用文件及目录,如src目录和*.iml文件
删除后项目目录
修改pom.xml中依赖,增加spring-boot-starter-parent
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.1.RELEASE</version></parent>复制代码

🌭2.创建子模块-dependencies(依赖层)

右击项目chat-boot,new ->Moudle新建模块chat-boot-dependencies
选择对应Module SDK版本,本人选择jdk1.8
填写子模块名 chat-boot-dependencies,然后检查对应GAV,点击Finish
生成子模块 chat-boot-dependencies如下图
删除 chat-boot-dependencies下无用文件及目录,如src目录,删除无用目录如下
完善 chat-boot-dependencies下pom.xml依赖, 常用依赖放入,作为 依赖主体,以下是本狗常用依赖,可酌情选择; 记得把packaging改为pom
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>chat-boot</artifactId><groupId>net.javadog.chat</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>chat-dependencies</artifactId><packaging>pom</packaging><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><mysql-connector-java.version>8.0.17</mysql-connector-java.version><druid.version>1.1.21</druid.version><mybatis-plus.version>3.4.1</mybatis-plus.version><fastjson.version>1.2.75</fastjson.version><hutool.version>5.5.8</hutool.version><lombok.versin>1.18.12</lombok.versin><easypoi.version>4.2.0</easypoi.version><springfox-swagger2.version>2.9.2</springfox-swagger2.version><springfox-swagger-ui.version>2.9.2</springfox-swagger-ui.version><knife4j.version>2.0.4</knife4j.version><weixin.version>4.4.5.B</weixin.version><shiro.version>1.3.2</shiro.version><jwt.version>3.2.0</jwt.version></properties><dependencyManagement><dependencies><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!-- 数据库驱动,可根据自己需要自行删减,默认使用mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-connector-java.version}</version></dependency><!--数据库连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><!--fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.version}</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.versin}</version></dependency><!--swagger2--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${springfox-swagger2.version}</version></dependency><!--swagger-ui--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>${springfox-swagger-ui.version}</version></dependency><!-- swagger接口文档 --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>${knife4j.version}</version></dependency><!--easypoi导入导出--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>${easypoi.version}</version></dependency><!--WxJava - 微信开发 Java SDK--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-miniapp</artifactId><version>${weixin.version}</version></dependency><!--整合Shiro安全框架--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><!--集成jwt实现token认证--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>${jwt.version}</version></dependency></dependencies></dependencyManagement></project>复制代码
🎯重点

此处用的标签是 dependencyManagement,

dependencyManagement只是声明依赖,并不实现引入,因此 子项目需要显示的声明需要用的依赖。如果 不在子项目中声明依赖,是不会从父项目中继承下来; 只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

🍪3.创建子模块-main(主启动层)

右击项目chat-boot,new ->Moudle新建模块chat-boot-main
选择对应Module SDK版本,本狗选择jdk1.8,点击Next
填写子模块名 chat-boot-main,然后检查对应GAV,点击Finish
生成子模块chat-boot-main如下图
完善chat-boot-main模块下pom.xml中依赖
  1. 引入必要依赖

  1. 完善profiles标签中环境相关

  1. 配置build标签中插件

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>chat-boot</artifactId><groupId>net.javadog.chat</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>chat-boot-main</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencyManagement><dependencies><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dependencies</artifactId><version>1.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!-- web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger2--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><!--swagger-ui--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId></dependency><!-- swagger接口文档 --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId></dependency></dependencies><build><finalName>chat</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>repackage</goal></goals></execution></executions><configuration><fork>true</fork></configuration></plugin></plugins><resources><resource><directory>src/main/webapp</directory><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources></build><profiles><profile><id>local</id><properties><spring.active>local</spring.active></properties><activation><activeByDefault>true</activeByDefault></activation></profile><profile><id>dev</id><properties><spring.active>dev</spring.active></properties></profile><profile><id>prod</id><properties><spring.active>prod</spring.active></properties></profile></profiles></project>复制代码
🎯重点
  • 配置引入依赖chat-boot-dependencies,用作此模块依赖引入

<dependencyManagement><dependencies><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dependencies</artifactId><version>1.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>复制代码
  • 配置build标签用于完善插件plugins,其中包含maven-compiler-plugin和maven-resources-plugin

<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>2.6</version><configuration><delimiters><delimiter>@</delimiter></delimiters><useDefaultDelimiters>false</useDefaultDelimiters></configuration></plugin></plugins><resources><resource><directory>src/main/webapp</directory><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources></build>复制代码
  • 配置profiles环境变量标签,用于方便打包切换,本狗设置了 local、dev、prod三种环境

<profiles><profile><id>local</id><properties><spring.active>local</spring.active></properties><activation><activeByDefault>true</activeByDefault></activation></profile><profile><id>dev</id><properties><spring.active>dev</spring.active></properties></profile><profile><id>prod</id><properties><spring.active>prod</spring.active></properties></profile></profiles>复制代码

操作可在IDEA右上角方便切换环境

💥切记一定主动Reload一下Maven依赖

💥切记一定主动Reload一下Maven依赖

💥切记一定主动Reload一下Maven依赖

在chat-boot-main模块中加入启动类,在src/main/java下右键New=>Java Class
录入启动类名ChatApplication
完善ChatApplication启动类代码
package net.javadog.chat;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author: hdx
 * @Date: 2023-01-28 11:24
 * @version: 1.0
 **/@SpringBootApplication@ServletComponentScan@Slf4j@EnableSwagger2@EnableKnife4jpublicclassChatApplication {
    publicstaticvoidmain(String[] args)throws UnknownHostException {
        // 启动类ConfigurableApplicationContextapplication= SpringApplication.run(ChatApplication.class, args);
        // 打印基础信息
        info(application);
    }

    staticvoidinfo(ConfigurableApplicationContext application)throws UnknownHostException {
        Environmentenv= application.getEnvironment();
        Stringip= InetAddress.getLocalHost().getHostAddress();
        Stringport= env.getProperty("server.port");
        Stringactive= env.getProperty("spring.profiles.active");
        StringcontextPath= env.getProperty("server.servlet.context-path");
        if (contextPath == null) {
            contextPath = "";
        }
        log.info("\n----------------------------------------------------------\n\t" +
                "欢迎访问  \thttps://blog.javadog.net\n\t" +
                "示例程序【" + active + "】环境已启动! 地址如下:\n\t" +
                "Local: \t\thttp://localhost:" + port + contextPath + "\n\t" +
                "External: \thttp://" + ip + ':' + port + contextPath + '\n' +
                "Swagger文档: \thttp://" + ip + ":" + port + contextPath + "/doc.html\n" +
                "----------------------------------------------------------");
    }
}
复制代码
配置application.yml文件

application.yml

#============================## server 配置#============================#server:port:82max-http-header-size:10240servlet:context-path:/chat/v1#============================## spring 配置#============================#spring:application:# 应用名name:chatprofiles:active:@spring.active@servlet:multipart:max-request-size:100MBmax-file-size:100MBjackson:time-zone:GMT+8date-format:yyyy-MM-ddHH:mm:ss.SSSlocale:zh_CNserialization:# 格式化输出indent_output:falsemain:allow-circular-references:true#解决swagger版本路径不兼容问题mvc:pathmatch:matching-strategy:ant_path_matcher#============================## mybatisplus 配置#============================#mybatis-plus:mapper-locations:classpath:mapper/*.xmlconfiguration:map-underscore-to-camel-case:truecache-enabled:truelazy-loading-enabled:truemultiple-result-sets-enabled:truelog-impl:org.apache.ibatis.logging.nologging.NoLoggingImplglobal-config:banner:falsedb-config:id-type:assign_idtable-underline:trueenable-sql-runner:true#数据库类型db-type:MYSQLconfiguration-properties:prefix:#如果数据库为postgresql,则需要配置为blobType: BINARYblobType:BLOB#如果数据库为oracle或mssql,则需要配置为boolValue: 1boolValue:true#============================## logging 配置#============================#logging:level:root:infofile:path:/root/javadog/chat/logs/${spring.application.name}/name:${spring.application.name}logback:rollingpolicy:max-history:7max-file-size:10MB#============================## file 配置#============================#file:# 静态附件前缀static-prefix:attach# 上传的文件对外暴露的访问路径access-path-pattern:/${file.static-prefix}/**# 文件上传目录upload-folder:/root/javadog/chat/# 文件上传最大max-post-size:10复制代码

application-local.yml

#服务配置server:port:8001max-http-header-size:10240# Mysql数据库spring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/chat-boot?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=trueusername:rootpassword:rootredis:host:localhostport:6379password:复制代码

application-dev.yml

#服务配置server:port:7001max-http-header-size:10240# mybatisplus 配置mybatis-plus:configuration:log-impl:org.apache.ibatis.logging.stdout.StdOutImpl复制代码

application-prod.yml

#服务配置server:port:8005复制代码

🌊顺便加一下logback-spring.xml 日志文件

<?xml version="1.0" encoding="UTF-8" ?><configurationscan="true"scanPeriod="60 seconds"debug="false"><conversionRuleconversionWord="clr"converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRuleconversionWord="wex"converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><conversionRuleconversionWord="wEx"converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/><propertyname="CONSOLE_LOG_PATTERN"value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/><propertyname="FILE_LOG_PATTERN"value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/><springPropertyscope="context"name="application.name"source="spring.application.name"defaultValue="javadog"/><springPropertyscope="context"name="logging.path"source="logging.file.path"defaultValue="logs"/><springPropertyscope="context"name="logging.file.max-size"source="logging.logback.rollingpolicy.max-size"defaultValue="10MB"/><springPropertyscope="context"name="logging.file.max-history"source="logging.logback.rollingpolicy.max-history"defaultValue="30"/><contextName>${application.name}</contextName><springProfilename="dev,prod"><!--输出到控制台--><appendername="console"class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern></encoder></appender><rootlevel="info"><appender-refref="console"/></root></springProfile><springProfilename="dev,test,prod"><!--输出到文件--><appendername="file-info"class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${logging.path}/info/${application.name}-info.log</file><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${logging.path}/info/${application.name}-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>${logging.file.max-size}</maxFileSize></timeBasedFileNamingAndTriggeringPolicy><!--只保留最近n天的日志--><maxHistory>${logging.file.max-history}</maxHistory></rollingPolicy><!-- 追加方式记录日志 --><append>true</append><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder></appender><appendername="file-warn"class="ch.qos.logback.core.rolling.RollingFileAppender"><filterclass="ch.qos.logback.classic.filter.LevelFilter"><level>warn</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><file>${logging.path}/warn/${application.name}-warn.log</file><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${logging.path}$/warn/${application.name}-warn.%d{yyyy-MM-dd}.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>${logging.file.max-size}</maxFileSize></timeBasedFileNamingAndTriggeringPolicy><!--只保留最近n天的日志--><maxHistory>${logging.file.max-history}</maxHistory></rollingPolicy><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder></appender><appendername="file-error"class="ch.qos.logback.core.rolling.RollingFileAppender"><filterclass="ch.qos.logback.classic.filter.LevelFilter"><level>error</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><file>${logging.path}/error/${application.name}-error.log</file><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${logging.path}/error/${application.name}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>${logging.file.max-size}</maxFileSize></timeBasedFileNamingAndTriggeringPolicy><!--只保留最近n天的日志--><maxHistory>${logging.file.max-history}</maxHistory></rollingPolicy><encoder><pattern>${FILE_LOG_PATTERN}</pattern></encoder></appender><rootlevel="INFO"><appender-refref="file-info"/><appender-refref="file-warn"/><appender-refref="file-error"/></root></springProfile></configuration>复制代码
启动一下项目试试,启动如下证明成功。如果报错少依赖请再拉一下Maven依赖!!!

🍇4.创建子模块-module(模块层)

右击项目chat-boot,new ->Moudle新建模块chat-boot-module
填写子模块名 chat-boot-module,然后检查对应GAV,点击Finish
生成子模块 chat-boot-module如下图
删除 chat-boot-module下无用文件及目录,如src目录,删除无用目录如下
自此外部大框架初步搭建成功
完善chat-boot-module下pom.xml依赖,如lombok,web等必要依赖
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>chat-boot</artifactId><groupId>net.javadog.chat</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>chat-boot-module</artifactId><packaging>pom</packaging><modules><module>chat-boot-common</module><module>chat-boot-controller</module><module>chat-boot-dao</module><module>chat-boot-dto</module><module>chat-boot-entity</module><module>chat-boot-service</module></modules><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencyManagement><dependencies><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dependencies</artifactId><version>${project.parent.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!-- web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--WxJava - 微信开发 Java SDK--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-miniapp</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId></dependency><!--swagger2--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><!--swagger-ui--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId></dependency><!--整合Knife4j--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId></dependency><!--整合Shiro安全框架--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId></dependency><!--jwt--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies></project>复制代码

一定要重新拉取依赖!一定要重新拉取依赖!一定要重新拉取依赖!


🍉5.创建chat-boot-module模块下对应功能分层

目前本狗分为如下6层
  • common-共通层

  • controller-控制器层

  • dao-数据持久层

  • dto-数据传输对象层

  • entity-实体层

  • service-业务逻辑层

依次按照上述添加模块方式进行新增子模块,本狗如下示例一个,其余都如法炮制

右击项目chat-boot-module,new ->Moudle新建模块chat-boot-common

一定看清楚父模块是否正确一定看清楚父模块是否正确一定看清楚父模块是否正确

确认父级模块后,点击Finish,生成chat-boot-common模块
依次按照上述方法,新建其他模块

chat-boot-controller模块

chat-boot-dao模块

chat-boot-dto模块

chat-boot-entity模块

chat-boot-service模块

总体模块雏形基本完成

🍧6.实际流程填充

  • 模拟正常前端请求到后台服务调用过程,进行实际代码补充

在chat-boot-entity下新建实体类User,在src/main/java下右键New=>Java Class,录入包名及类名
package net.javadog.chat.entity;

import lombok.Data;

/**
 * @author: hdx
 * @Date: 2023-01-28 14:26
 * @version: 1.0
 **/@DatapublicclassUser {

    private Long id;

    private String username;

    private String idCard;
}

复制代码

在chat-boot-dto下新建目 request和response,分别代表 请求传输对象和返回传输对象,并分别在目录下创建UserRequest.java和UserResponse.java
package net.javadog.chat.request;

import lombok.Data;

/**
 * @author: hdx
 * @Date: 2023-01-28 14:59
 * @version: 1.0
 **/@DatapublicclassUserRequest {

    private Long id;

    private String username;
}
复制代码
package net.javadog.chat.response;

import lombok.Data;

/**
 * @author: hdx
 * @Date: 2023-01-28 14:59
 * @version: 1.0
 **/@DatapublicclassUserResponse {

    private Long id;

    private String username;
}
复制代码

在chat-boot-dao下修改chat-boot-dao模块下修改pom.xml文件依赖,引入chat-boot-entity;并增对应UserMapper.java
package net.javadog.chat.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.javadog.chat.entity.User;

/**
 * 用户mapper
 *
 * @author: hdx
 * @Date: 2023-01-10 11:43
 * @version: 1.0
 **/publicinterfaceUserMapperextendsBaseMapper<User> {
}

复制代码
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>chat-boot-module</artifactId><groupId>net.javadog.chat</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>chat-boot-dao</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-entity</artifactId><version>${project.parent.version}</version></dependency></dependencies></project>复制代码

在chat-boot-service下新建目录service和impl,并在对应目录下新建UserService.java和UserServiceImpl.java,并修改chat-boot-service模块下修改pom.xml文件依赖,引入chat-boot-dto,chat-boot-dao
package net.javadog.chat.service;

import com.baomidou.mybatisplus.extension.service.IService;
import net.javadog.chat.entity.User;

/**
 * 用户接口
 *
 * @author: hdx
 * @Date: 2023-01-10 11:53
 * @version: 1.0
 **/publicinterfaceUserServiceextendsIService<User> {

}

复制代码
package net.javadog.chat.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.javadog.chat.entity.User;
import net.javadog.chat.mapper.UserMapper;
import net.javadog.chat.service.UserService;
import org.springframework.stereotype.Service;

/**
 * 用户接口实现类
 *
 * @author: hdx
 * @Date: 2023-01-10 11:55
 * @version: 1.0
 **/@ServicepublicclassUserServiceImplextendsServiceImpl<UserMapper, User> implementsUserService {

}
复制代码
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>chat-boot-module</artifactId><groupId>net.javadog.chat</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>chat-boot-service</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dao</artifactId><version>${project.parent.version}</version></dependency><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dto</artifactId><version>${project.parent.version}</version></dependency></dependencies></project>复制代码

在chat-boot-controller创建UserController.java,并修改chat-boot-controller模块下修改pom.xml文件依赖,引入chat-boot-dto,chat-boot-service
package net.javadog.chat.controller;

import cn.hutool.core.bean.BeanUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.javadog.chat.entity.User;
import net.javadog.chat.request.UserRequest;
import net.javadog.chat.response.UserResponse;
import net.javadog.chat.service.UserService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 用户控制器
 *
 * @author: hdx
 * @Date: 2022-12-07 15:48
 * @version: 1.0
 **/@Api(tags = "用户控制器")@RestController@RequestMapping("/user")publicclassUserController {

    @Resourceprivate UserService userService;

    @ApiOperation(value = "用户详情", notes = "用户详情")@GetMappingpublic UserResponse detail(UserRequest userRequest){
        UserResponseuserResponse=newUserResponse();
        Useruser= userService.getById(userRequest.getId());
        BeanUtil.copyProperties(user, userResponse);
        return userResponse;
    }

}

复制代码

🎯重要补充1.切记修改chat-boot-main下的pom.xml依赖,将chat-boot-controller模块加入2.切记修改chat-boot-main下的pom.xml依赖,将chat-boot-dao模块加入3.切记修改启动类ChatApplication中加入@MapperScan注解

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>chat-boot</artifactId><groupId>net.javadog.chat</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>chat-boot-main</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencyManagement><dependencies><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dependencies</artifactId><version>1.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!-- web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger2--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><!--swagger-ui--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId></dependency><!-- swagger接口文档 --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId></dependency><!-- controller --><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-controller</artifactId><version>${project.parent.version}</version></dependency><!-- dao --><dependency><groupId>net.javadog.chat</groupId><artifactId>chat-boot-dao</artifactId><version>${project.parent.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>2.6</version><configuration><delimiters><delimiter>@</delimiter></delimiters><useDefaultDelimiters>false</useDefaultDelimiters></configuration></plugin></plugins><resources><resource><directory>src/main/webapp</directory><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources></build><profiles><profile><id>local</id><properties><spring.active>local</spring.active></properties><activation><activeByDefault>true</activeByDefault></activation></profile><profile><id>dev</id><properties><spring.active>dev</spring.active></properties></profile><profile><id>prod</id><properties><spring.active>prod</spring.active></properties></profile></profiles></project>复制代码
package net.javadog.chat;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author: hdx
 * @Date: 2023-01-28 11:24
 * @version: 1.0
 **/@SpringBootApplication@ServletComponentScan@Slf4j@EnableSwagger2@EnableKnife4j@MapperScan(basePackages = {"net.javadog.chat.mapper"})publicclassChatApplication {
    publicstaticvoidmain(String[] args)throws UnknownHostException {
        // 启动类ConfigurableApplicationContextapplication= SpringApplication.run(ChatApplication.class, args);
        // 打印基础信息
        info(application);
    }

    staticvoidinfo(ConfigurableApplicationContext application)throws UnknownHostException {
        Environmentenv= application.getEnvironment();
        Stringip= InetAddress.getLocalHost().getHostAddress();
        Stringport= env.getProperty("server.port");
        Stringactive= env.getProperty("spring.profiles.active");
        StringcontextPath= env.getProperty("server.servlet.context-path");
        if (contextPath == null) {
            contextPath = "";
        }
        log.info("\n----------------------------------------------------------\n\t" +
                "欢迎访问  \thttps://blog.javadog.net\n\t" +
                "示例程序【" + active + "】环境已启动! 地址如下:\n\t" +
                "Local: \t\thttp://localhost:" + port + contextPath + "\n\t" +
                "External: \thttp://" + ip + ':' + port + contextPath + '\n' +
                "Swagger文档: \thttp://" + ip + ":" + port + contextPath + "/doc.html\n" +
                "----------------------------------------------------------");
    }
}
复制代码

🦔7.示例DB更新

  • 模拟正常前端请求到后台服务调用过程,进行实际代码补充

DROPTABLE IF EXISTS `user`;
CREATETABLE `user`  (
  `id` bigint(20) NOTNULL COMMENT 'id',
  `username` varchar(255) CHARACTERSET utf8 COLLATE utf8_general_ci NULLDEFAULTNULL COMMENT '用户名',
  `id_card` varchar(255) CHARACTERSET utf8 COLLATE utf8_general_ci NULLDEFAULTNULL COMMENT '身份证',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTERSET= utf8 COLLATE= utf8_general_ci ROW_FORMAT =Dynamic;

-- ------------------------------ Records of user-- ----------------------------INSERTINTO `user` VALUES (1, 'JavaDog', '123123');
复制代码

🧩8.访问测试

浏览器访问 http://localhost:8001/chat/v1/user?id=1

测试成功如下图所示

总结

以上示例只是简单示范分层思路,其中代码逻辑实现方式有很多种,大家选取适用自己就好,希望自己的思路能对大家有帮助

如遇缺少依赖情况,一定要重新拉取依赖!

Spring Boot项目中的Controller、Service、Mapper和Entity层的作用与联系 Controller层是Spring Boot应用程序的入口点,通常处用于理请求的输入和输出,并负责验证输入数据的有效性。它将请求参数传递给Service层,然后将Service层的处理结果封装成适当的响应返回给客户端。 阅读详情

相关推荐

springboot项目切分多个module

实际上我们的项目肯定不是,初始化一个springboot项目就完事了,我们可能要分成一个个子模块,互相依赖的情况。中间有的模块就是提供DAO这些基础,有的是提供API接口服务的,有的则是独立的给APP或者web端接口的。 如何去划分模块: (1)创建项目 创建一个maven项目,作为总的依赖,要把src里面都删除,仅仅留下来个POM文件作为root和一个说明文档就可以了。 (2)先建一个module 这里创建module跟创建maven工程一样,我们新建的项目路径都尽量统一,比如: module1 com.

FeiChangWuRao的博客 3682

Laravel企业信息化管理平台

一款 PHP 语言基于 Laravel5.8、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,框架自研了一套个性化的组件,实现了可插拔的组件式开发方式:单图上传、多图上传、下拉选择、开关按钮、单选按钮、多选按钮、图片裁剪等等一系列个性化、轻量级的组件,是一款真正意义上实现组件化开发的敏捷开发框架,框架已集成了完整的RBAC权限架构和常规基础模块,同时支持多主题切换,可以根据自己喜欢的风格选择

weixin_50196917的博客 5793

手把手教你从零开始搭建SpringBoot后端项目框架

原料 新鲜的IntelliJ IDEA、一双手、以及电脑一台。 搭建框架 新建项目 打开IDE,点击File -> New Project。在左侧的列表中的选择Maven项目,点击Next。 填写GroupId和ArtifactId 什么是GroupId和ArtifactId?大家可以参考一下google出来的定义,可以参考一下。 GroupID是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。 ArtifactID就是项目的唯一的标识符,实际对应项目的名称,就

SH的全栈笔记 1341

手把手教你springboot集成mybatis

很多小伙伴工作多年,但是在每次开始一个新项目的时候都要重新开始搭建项目。另一个就是新手小伙伴对于项目如何从零开始搭建的还存在疑问。在这片文章中,正好一次性解决这两个问题。这是该项目的首先,我们需要创建一个springboot项目。...

m0_67322837的博客 8723

SpringBoot多模块项目开发(Maven多模块项目)

在需要统一版本的位置,使用 ${自定义标签名} 引用声明的版本号。另外,自定义标签声明数据的配置并不是只能用于声明依赖的版本号,凡是需要统一声明后再引用的场合都可以使用,例如:统一配置项目构建的源码的字符集格式。xml复制代码。

m0_64363449的博客 5906

IDEA 搭建springboot多模块项目

为什么要建多模块项目?随着业务发展,项目参与人员变多,业务变复杂,所有的代码都在一个结构下,就会变得不直观,同时耦合度可能比较高。另外一个问题就是,在多服务的场景下,要给外部服务提供接口了(比如要提供对外的dubbo接口),如果是单体结构,只能整个模块打个jar出去,不优雅,不然还得重新做多模块拆分,麻烦。还有一个问题,可能一些通用的类在好几个工程里都有,多模块结构可以把通用的类放到一起,打包出去给其它服务用。所以,对于可预见未来的中大型项目,最好是刚开始就直接多模块搭建,对于小型项目,单结构即可

wk的专栏 3088

手把手教你通过SpringBoot实现邮箱注册码验证

一、前言 注册一个系统成为用户,一般会要求用户留下一个邮件地址作为联系方式,就象我们去银行开户时银行会让我们留个手机号码一样。为了证明注册的邮箱地址是本人的,系统会向邮箱发送一串验证码,用户收取该验证码后在注册页面上输入验证码连同其他信息发往后台进行验证。 ...

我的博客 1万+

Frida三层次钩子快速逆向VMP+OLLVM加固APK

VMP(虚拟机保护)和OLLVM(控制流平坦化)是Android应用常见的双重混淆技术,其核心原理是将Java逻辑虚拟化、Native代码控制流打散,从而阻断传统静态分析与简单Hook。但任何混淆都必须在CPU上执行,因此必然暴露JNI注册行为、ABI参数传递规律及系统调用痕迹。基于此,Frida可通过跨层联动——从JNI_OnLoad捕获Native库加载、在VMP解释器入口截获字节码上下文、于关键系统调用(如read/gettimeofday)反向追踪数据流——构建可观测、可复现的动态分析链。该方法无需

weixin_30888413的博客 1002

手把手教你从0搭建SpringBoot项目

用到的工具:idea 2021、Maven 3.6.3、postman 框架:SpringBoot、Mybatis 数据库:Mysql8.0.30。

CZ101的博客 1万+

PX4与ROS协同仿真:从键盘控制到无人机自主飞行

本文详细介绍了如何搭建PX4与ROS协同仿真环境,实现从键盘控制到无人机自主飞行的完整流程。通过XTDrone项目整合PX4飞控、ROS通信框架与Gazebo物理引擎,逐步讲解环境配置、键盘控制实现原理,并深入剖析了迈向Offboard模式实现自主飞行的核心代码与数据流,为无人机算法开发与测试提供了安全的仿真沙盒。

weixin_29169899的博客 498

CLCD土地覆盖数据在ArcGIS中的实战应用:从导入到空间分析的完整指南

本文详细介绍了CLCD土地覆盖数据在ArcGIS中的实战应用,从数据导入到空间分析的完整流程。涵盖坐标系转换、数据质量检查、土地利用变化检测等核心技术,并分享城市扩张模拟和跨数据集融合等高级应用技巧,帮助研究者高效利用这一权威数据集进行环境监测和城市规划。

weixin_29292535的博客 595

Springboot的项目如何分层

每个人、每个开发团队的规范习惯都不太一样,没有固定标准,合适的才是最好的。这里记录下我习惯的一种springboot项目分层方式

代码小郭的技术博客 1245

MATLAB基础应用精讲-【强化学习】Actor - Critic 算法(附python代码实现)

这种架构结合了策略梯度方法(Policy - Gradient Methods)和价值函数估计方法(Value Function Estimation Methods)的优点。在强化学习中,智能体(Agent)需要通过与环境(Environment)的交互来学习最优的行为策略,以获得最大的累积奖励(Cumulative Reward)。

qq_36130719的博客 363

基于SpringBoot构建分模块项目

基于SpringBoot构建分模块项目前言~~步骤过于详细,多图慎入!!!~~构建创建父模块创建 erp-common创建 erp-service创建erp-service-impl创建erp-web-repertory创建其余web模块依赖运行扩展占位符 前言 步骤过于详细,多图慎入!!! 假设一个场景,要开发一个4s店维修部的办公系统,其功能有:前台接待,维修抢单,财务结算,库存管理。于是...

L_Wierpuller的博客 4384

国科大学习资料--模式识别与机器学习(黄庆明)--期末复习题2(含答案)

国科大学习资料–模式识别与机器学习(黄庆明)–期末复习题2(含答案) 国科大学习资料–模式识别与机器学习(黄庆明)–期末复习题2(含答案) 国科大学习资料–模式识别与机器学习(黄庆明)–期末复习题2(含答案) ...

无名何许人的博客 1万+

基于STM32的智能血氧、心率、体温、血压监测系统

摘要:本文设计了一款基于STM32F103C8T6的多功能健康监测系统,可实时检测血氧、心率、体温和血压四项生理参数。系统集成MAX30102、DS18B20等传感器模块,采用OLED显示和蓝牙无线传输技术,实现一键血压测量、阈值报警及手机APP数据管理功能。硬件设计包含传感器采集、电源管理、显示报警等模块;软件采用模块化架构,实现数据采集处理、蓝牙通讯等功能。测试表明系统测量准确可靠,为家庭健康监测提供了便携解决方案。未来可扩展更多监测参数和智能分析功能。

3254968421的博客 771

springboot项目如何合理分层呢

在Java Spring项目中,合理的分层结构有助于实现良好的系统架构,提高代码的可维护性、可扩展性和测试性。通过定义专用的请求和响应实体类,可以帮助减少和避免一些潜在的安全问题,包括隐含的恶意代码。合理的分层设计可以提高系统的可维护性、可扩展性和测试性。在Java Spring项目中,常见的分层包括表现层、业务逻辑层、数据访问层、领域层、配置层和辅助层。每一层都有明确的职责,通过接口和依赖注入进行解耦,遵循设计原则,有助于构建一个清晰、稳定的应用程序架构。

一起来研究langchain和langchain-chatchat 1491

HotSpot G1 GC 的分区记账、SATB 并发标记与停顿目标调优解析

线上GC毛刺该调停顿目标、加大新生代还是换收集器?本文从HotSpot G1的设计出发,梳理分区与巨型对象、卡表与记忆集、写屏障与细化线程、停顿预测、SATB并发标记、自适应IHOP、混合回收规则及Full GC兜底,并注明JDK8至JDK27的版本差异。文中在JDK8与JDK17上实测:停顿目标从200ms降到20ms,伊甸区缩小四成、P99下降但仍超目标;巨型对象会反复触发又撤销并发标记;JDK17并行Full GC平均停顿约为JDK8的三成。最后给出日志解读、参数清单、调优流程与选型。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 170万+

Springboot的项目分层

String类 Scanner类

qq_46379459的博客 5645

[企业AI落地] RAG 知识库系统在多租户环境下的细粒度权限隔离设计

多租户 RAG 系统真正的风险不只是搜不到,而是把不该看到的内容查出来、说出来、写回去。本文结合多客户售后知识助手场景,用元数据结构、向量检索过滤、回答策略和审计回写示例拆解租户、资源、检索、生成、审计五层权限边界。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 220

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

SpringBoot多模块

SpringBoot多模块项目的搭建

qq_73639699的博客 4514

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

SpringBoot 多模块项目搭建:service/dao/web分层设计

在实际企业开发中,简单的单模块 SpringBoot 项目只能用来快速 Dem)o 或小型应用,一旦业务复杂、团队人数变多、需求迭代加快,单模块就会暴露出。关注我,持续更新 SpringBoot 企业级实战教程,从工程搭建到微服务、高并发、分布式架构,带你一步步成长为后端大牛!只要按照这套结构搭建项目,你的工程规范度、可维护性、可扩展性都会直接达到企业级标准。,正是解决这些问题的标准方案。代码混乱、职责不清、难以维护、编译打包慢、不利于后期微服务拆分。职责清晰、分层解耦、易于维护、易于扩展、便于团队协作。

。。。 1478

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

手把手教你分析开源项目

狂神手把手教你分析开源项目

写代码的渣渣苏 2044
上一篇: 互联网大厂 1000+ 面试题附答案详解(整理版),最全面详细!
下一篇: 起飞!开啃399页Java架构知识点,涨薪25K
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值