<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          從零教你SpringBoot+Gradle+ MyBatisPlus3.x搭建的企業(yè)級后臺分離框架

          共 39709字,需瀏覽 80分鐘

           ·

          2021-08-12 12:01

          來源:https://mp.weixin.qq.com/s/TZMPDndgMbBA-pTTYtUTcQ

          1、技術選型

          • 解析器:FastJSON
          • 開發(fā)工具:JDK1.8 、Gradle、IDEA
          • 技術框架:SpringBoot 2.1.5.RELEASE
          • ORM技術:MyBatisPlus3.1.2
          • 數(shù)據(jù)庫:MySQL8.0.21
          • Apache 工具:HttpClient、Lang3
          • Git代碼版本控制
          • Web服務器:undertow
          • hutool 國產(chǎn)工具類包
          • lombok 簡化代碼工具
          • druid 數(shù)據(jù)庫連接池框架

          2、Spring Boot 發(fā)展路線簡要描述

          • 隨著動態(tài)語言的流行 (Ruby、Groovy、Scala、Node.js),Java 的開發(fā)顯得格外的笨重:繁多的配置、低下的開發(fā)效率、復雜的部署流程以及第三方技術集成難度大。
          • 在上述環(huán)境下,Spring Boot 應運而生。它使用“習慣優(yōu)于配置”(項目中存在大量的配置,此外還內(nèi)置了一個習慣性的配置,讓你無需手動進行配置)的理念讓你的項目快速的運行起來。使用 Spring Boot 很容易創(chuàng)建一個獨立運行(運行 Jar,內(nèi)嵌 Servlet 容器)準生產(chǎn)級別的基于 Spring 框架的項目,使用 Spring Boot 你可以不用或者只需很少的 Spring 配置。

          3、 SpringBoot插件使用

          • spring-boot-devtools 實現(xiàn)熱部署,實際開發(fā)過程中,修改應用的業(yè)務邏輯時常常需要重啟應用,這顯得非常繁瑣,降低了開發(fā)效率,所以熱部署對于開發(fā)來說顯得十分必要了
          • spring-boot-starter-aop 此插件沒什么好說的了,aop是spring的兩大功能模塊之一,功能非常強大,為解耦提供了非常優(yōu)秀的解決方案。如:面向方面編程
          • spring-boot-starter-undertow 與spring boot 內(nèi)置undertow 插件
          • spring-boot-starter-test 測試工具
          • mybatis-plus-boot-starter 與spring boot整合MyBatisPlus的jar
          • spring-boot-configuration-processor 整合SpringBoot配置提示

          4、fastJson

          • 阿里JSON解析器,詳細文檔請看官方 https://github.com/alibaba/fastjson

          5、Hutool

          • Hutool是一個Java工具包,也只是一個工具包,它幫助我們簡化每一行代碼,減少每一個方法,讓Java語言也可以“甜甜的”。Hutool最初是我項目中“util”包的一個整理,后來慢慢積累并加入更多非業(yè)務相關功能,并廣泛學習其它開源項目精髓,經(jīng)過自己整理修改,最終形成豐富的開源工具集。

          6、Gradle

          • Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化構建開源工具。它使用一種基于Groovy的特定領域語言(DSL)來聲明項目設置,目前也增加了基于Kotlin語言的kotlin-based DSL,拋棄了基于XML的各種繁瑣配置
          • 官方 https://gradle.org/
          • 不會Gradle的先自己補習一下,比如:安裝Gradle,配置環(huán)境變量,一些jar引入如何配置,基本使用怎么使用

          7、工程結構

          • 此工程是通過Kotlin+SpringBoot+MyBatisPlus搭建最簡潔的前后端分離框架 框架升級Java語言SpringBoot+MyBatisPlus3.X+Gradle版本的框架,想學習Kotlin版本的請點擊藍色文章進行下載源代碼。

          8、Gradle配置

          plugins {
              id 'java'
              id 'idea'
          }

          /**
           * 使用Groovy語言語法定義版本號變量
           */
          def spring_boot_version = "2.1.5.RELEASE"
          def mybatis_plus_version = "3.1.2"
          def mysql_version = "8.0.21"
          def druid_version = "1.1.23"
          def logback_version = "1.2.1"
          def fastjson_version = "1.2.73"
          def lombok_version = "1.18.12"
          def lang_version = "3.4"
          def io_version = "2.6"
          def guava_version = "18.0"
          def hutool_version = "5.3.10"

          group = 'com.flong'
          version = '0.0.1-SNAPSHOT'

          //jdk版本
          sourceCompatibility = JavaVersion.VERSION_1_8
          targetCompatibility = JavaVersion.VERSION_1_8

          repositories {
              //指定阿里云鏡像
              maven {
                  url 'http://maven.aliyun.com/nexus/content/groups/public/'
              }
              mavenLocal()
              mavenCentral()
          }

          /**
           * 1、implementation 履行 、compile 編譯
           * 2、Gradle使用雙引號可 ${變量}可以放入引號里面,單引號是不可以的。
           * 3、Gragle使用lombok需要引入annotationProcessor注解,否則不能使用lombok.
           * 4、mybatis-plus3.2.x以上版本引用了Kotlin的支持
           * 5、高版本Springboogt在spring-boot-dependencies-2.3.0.RELEASE.pom里面引入了mysql8.0.2的`<mysql.version>8.0.20</mysql.version>`配置
           */
          dependencies {

              implementation "org.springframework.boot:spring-boot-starter:${spring_boot_version}"
              //排除tomcat使用undertow
              compile("org.springframework.boot:spring-boot-starter-web:${spring_boot_version}") {
                  exclude module: "spring-boot-starter-tomcat"
              }
              compile "org.springframework.boot:spring-boot-starter-undertow:${spring_boot_version}"

              //runtime group: 'mysql', name: 'mysql-connector-java', version: '5.1.42'
              compile "org.springframework.boot:spring-boot-devtools:${spring_boot_version}"
              compile "org.springframework.boot:spring-boot-configuration-processor:${spring_boot_version}"
              compile "org.springframework.boot:spring-boot-starter-test:${spring_boot_version}"
              compile "com.baomidou:mybatis-plus-extension:${mybatis_plus_version}"
              compile "com.baomidou:mybatis-plus-boot-starter:${mybatis_plus_version}"
              compile "mysql:mysql-connector-java:${mysql_version}"
              compile "com.alibaba:druid:${druid_version}"
              compile "ch.qos.logback:logback-classic:${logback_version}"
              compile "com.alibaba:fastjson:${fastjson_version}"
              annotationProcessor "org.projectlombok:lombok:${lombok_version}"
              compileOnly "org.projectlombok:lombok:${lombok_version}"
              //testAnnotationProcessor "org.projectlombok:lombok:${lombok_version}"
              //testCompileOnly "org.projectlombok:lombok:${lombok_version}"
              compile "org.apache.commons:commons-lang3:${lang_version}"
              compile "commons-io:commons-io:${io_version}"
              compile "com.google.guava:guava:${guava_version}"
              compile  "cn.hutool:hutool-all:${hutool_version}"
          }

          tasks.withType(JavaCompile) {
              options.encoding = "UTF-8"
          }

          [compileJava, javadoc, compileTestJava]*.options*.encoding = "UTF-8"

          9、數(shù)據(jù)庫SQL腳本

          • -- 創(chuàng)建表字段不建議用is開頭,在我Kotlin+Springboot+MyBatisPlus2.x整合也提到此問題,
          • -- 故此整合MyBatisPlus3.x版本,把表的is_deleted字段修改成del_flag,阿里開發(fā)手冊也提到此問題.
          DROP TABLE IF EXISTS `t_user`;
          CREATE TABLE `t_user` (
            `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
            `user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用戶Id主鍵,IdWork生成',
            `user_name` varchar(255) DEFAULT '' COMMENT '用戶名',
            `pass_word` varchar(255) DEFAULT '' COMMENT '密碼',
            `del_flag` int(2) unsigned NOT NULL DEFAULT '0' COMMENT '是否刪除,0-不刪除,1-刪除',
            `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
            PRIMARY KEY (`user_id`) USING BTREE,
            UNIQUE KEY `id` (`id`)USING BTREE
          )ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='用戶表';

          10、SpringBoot與MyBatisPlus3整合分頁代碼

          import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          @Configuration
          public class MyBatisPlusConfig {

              /**
               * 分頁插件
               */
              @Bean
              public PaginationInterceptor paginationInterceptor() {
                  return new PaginationInterceptor();
              }
          }  

          11、SpringBoot與MyBatisPlus3分頁條件組裝器

          package com.flong.springboot.core.util;

          import cn.hutool.core.util.StrUtil;
          import com.baomidou.mybatisplus.annotation.TableField;
          import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
          import com.baomidou.mybatisplus.core.toolkit.Wrappers;
          import com.flong.springboot.core.vo.Condition;

          import java.lang.reflect.Field;
          import java.util.List;

          import com.flong.springboot.core.enums.JoinType;
          import com.flong.springboot.core.exception.BaseException;

          /**
           * 將condition數(shù)據(jù)轉換成wrapper
           */
          public class BuildConditionWrapper {

              public static <T> QueryWrapper<T> build(List<Condition> conditions, Class<T> clazz) {
                  //初始化mybatis條件構造器
                  QueryWrapper wrapper = Wrappers.query();
                  if (conditions == null || conditions.size() == 0) {
                      return wrapper;
                  }
                  try {
                      for (int i = 0; i < conditions.size(); i++) {
                          Condition condition = conditions.get(i);

                          if (condition.getFieldName() == null) {
                              throw new BaseException("調(diào)用搜索接口時,缺少關鍵字[fieldName]!");
                          }
                          //列名稱
                          String columnName = getColumnName(condition.getFieldName(), clazz);

                          if (condition == null || condition.getOperation() == null) {
                              throw new BaseException("操作符不能為空!");
                          }

                          switch (condition.getOperation()) {
                              //等于
                              case EQ:
                                  wrapper.eq(columnName, condition.getValue());
                                  break;
                              //大于
                              case GT:
                                  wrapper.gt(columnName, condition.getValue());
                                  break;
                              //小于
                              case LT:
                                  wrapper.lt(columnName, condition.getValue());
                                  break;
                              //不等于
                              case NEQ:
                                  wrapper.ne(columnName, condition.getValue());
                                  break;
                              //大于等于
                              case GTANDEQ:
                                  wrapper.ge(columnName, condition.getValue());
                                  break;
                              //小于等于
                              case LTANDEQ:
                                  wrapper.le(columnName, condition.getValue());
                                  break;
                              case LIKE:
                                  wrapper.like(columnName, condition.getValue());
                                  break;
                              case ISNULL:
                                  wrapper.isNull(columnName);
                                  break;
                              case IN:
                                  //value :1,2,3,4,5,6
                                  wrapper.inSql(columnName, condition.getValue());
                                  break;
                              default:
                                  break;
                          }
                          if (condition.getJoinType() == JoinType.OR && i < conditions.size() - 1) {
                              //下個條件為or連接且非最后一個條件,使用or進行連接
                              wrapper.or();
                          }
                      }
                      return wrapper;
                  } catch (Exception e) {
                      throw new BaseException("查詢條件不存在");
                  }
              }

              /**
               * @Descript 此條件構建包裝器方法是支持多個表組裝成SQL字段的虛擬表,不支持實際存在的表
               * @Date 2019/6/21 13:32
               * @Author liangjl
               */
              public static <T> QueryWrapper<T> buildWarpper(List<Condition> conditions) {
                  //初始化mybatis條件構造器
                  QueryWrapper wrapper = Wrappers.query();
                  if (conditions == null || conditions.size() == 0) {
                      return wrapper;
                  }
                  try {
                      for (int i = 0; i < conditions.size(); i++) {
                          Condition condition = conditions.get(i);
                          if (condition.getFieldName() == null) {
                              throw new BaseException("調(diào)用搜索接口時,缺少關鍵字[fieldName]!");
                          }
                          //列名稱
                          String columnName = condition.getFieldName();
                          if (condition == null || condition.getOperation() == null) {
                              throw new BaseException("操作符不能為空!");
                          }
                          switch (condition.getOperation()) {
                              //等于
                              case EQ:
                                  wrapper.eq(columnName, condition.getValue());
                                  break;
                              //大于
                              case GT:
                                  wrapper.gt(columnName, condition.getValue());
                                  break;
                              //小于
                              case LT:
                                  wrapper.lt(columnName, condition.getValue());
                                  break;
                              //不等于
                              case NEQ:
                                  wrapper.ne(columnName, condition.getValue());
                                  break;
                              //大于等于
                              case GTANDEQ:
                                  wrapper.ge(columnName, condition.getValue());
                                  break;
                              //小于等于
                              case LTANDEQ:
                                  wrapper.le(columnName, condition.getValue());
                                  break;
                              case LIKE:
                                  wrapper.like(columnName, condition.getValue());
                                  break;
                              case IN:
                                  //value :1,2,3,4,5,6
                                  wrapper.inSql(columnName, condition.getValue());
                                  break;
                              default:
                                  break;
                          }
                          if (condition.getJoinType() == JoinType.OR && i < conditions.size() - 1) {
                              //下個條件為or連接且非最后一個條件,使用or進行連接
                              wrapper.or();
                          }
                      }
                      return wrapper;
                  } catch (Exception e) {
                      throw new BaseException("查詢條件不存在");
                  }
              }

              /***
               * @Descript 獲取指定實體Bean的字段屬性
               * @Date 2019/6/19 14:51
               * @Author liangjl
               */
              public static String getColumnName(String fieldName, Class clazz) {
                  try {
                      //獲取泛型類型字段
                      Field field = clazz.getDeclaredField(fieldName);
                      TableField tableFieldAnno = field.getAnnotation(TableField.class);
                      String columnName = "";
                      //獲取對應數(shù)據(jù)庫字段
                      if (tableFieldAnno != null && StrUtil.isNotBlank(tableFieldAnno.value())) {
                          //已定義數(shù)據(jù)庫字段,取定義值
                          columnName = tableFieldAnno.value();
                      } else {
                          //未指定數(shù)據(jù)庫字段,默認駝峰轉下劃線
                          columnName = NamingStrategyUtils.camelToUnderline(field.getName());
                      }
                      return columnName;
                  } catch (NoSuchFieldException e) {
                      throw new BaseException("查詢條件不存在");
                  }
              }

          }

          12、 實體

          import com.baomidou.mybatisplus.annotation.IdType;
          import com.baomidou.mybatisplus.annotation.TableId;
          import com.baomidou.mybatisplus.annotation.TableLogic;
          import com.baomidou.mybatisplus.annotation.TableName;
          import com.baomidou.mybatisplus.extension.activerecord.Model;
          import lombok.*;

          import java.io.Serializable;
          import java.util.Date;


          @Data
          @Builder
          @AllArgsConstructor
          @NoArgsConstructor
          @EqualsAndHashCode(callSuper=false)
          @TableName("t_user")
          public class User extends Model<User> implements Serializable {

              @TableId(type = IdType.ID_WORKER)
              private Long userId;

              /**
               * 用戶名
               */

              private String userName;
              /**
               * 密碼
               */
              private String passWord;
              /**
               * 邏輯刪除(0-未刪除,1-已刪除)
               */
              @TableLogic
              private String delFlag;

              /**
               * 創(chuàng)建時間,允許為空,讓數(shù)據(jù)庫自動生成即可
               */
              private Date createTime;
          }

          13、 Mapper

          • BaseMapper是繼承了mybatisplus底層的代碼
          import com.baomidou.mybatisplus.core.mapper.BaseMapper;
          import com.flong.springboot.modules.entity.User;

          public interface UserMapper extends BaseMapper<User> {

          }

          14、 Service

          • ServiceImplr是繼承了mybatisplus底層的代碼
          import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
          import com.flong.springboot.modules.entity.User;
          import com.flong.springboot.modules.mapper.UserMapper;
          import org.springframework.stereotype.Service;

          @Service
          public class UserService extends ServiceImpl<UserMapper, User> {

          }

          15 、controller

          • 控制層主要實現(xiàn)CURD,增加,修改,查詢,刪除、分頁無大常規(guī)操作接口操作

          • 用戶分頁,參數(shù)有多個使用下標索引進行處理.如果有兩個參數(shù)(如用戶名和地址):conditionList[0].fieldName=userName、 conditionList[0].fieldName=address

          • 查詢是通過反射fieldName進行去獲取表結構userName、address 字段的。

          • 未轉碼請求分頁地址: http://localhost:7011/user/page?conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=周

          • 已轉碼請求分頁地址: http://localhost:7011/user/page?conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=%E5%91%A8

          package com.flong.springboot.modules.controller;

          import com.alibaba.fastjson.JSON;
          import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
          import com.baomidou.mybatisplus.core.metadata.IPage;
          import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
          import com.flong.springboot.modules.entity.User;
          import com.flong.springboot.modules.mapper.UserMapper;
          import com.flong.springboot.modules.service.UserService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.web.bind.annotation.*;
          import com.flong.springboot.core.vo.Conditions;
          import com.flong.springboot.core.util.BuildConditionWrapper;

          import java.util.List;

          /**
           * @Author:liangjl
           * @Date:2020-08-16
           * @Description:用戶控制層
           */
          @RestController
          @RequestMapping("/user")
          public class UserController {

              @Autowired
              private UserMapper userMapper;

              @Autowired
              private UserService userService;

              /**
               * 添加
               */
              @RequestMapping("/add")
              public void add() {
                  userMapper.insert(User.builder().userName("周伯通").passWord("123456").build());
              }

              /**
               * 修改
               * @param user
               */
              @PutMapping("/updateById")
              public void updateById(@RequestBody User user) {
                  userMapper.updateById(user);
              }
              /**
               * 刪除通過多個主鍵Id進行刪除
               * @param ids
               */
              @DeleteMapping("/deleteByIds")
              public void deleteByIds(@RequestBody List<String> ids) {
                  userMapper.deleteBatchIds(ids);
              }

              /**
               * 通過指定Id進行查詢
               *
               * @param userId
               */
              @GetMapping("/getOne/{userId}")
              public void getOne(@PathVariable("userId") Long userId) {
                  User user = userMapper.selectById(userId);
                  System.out.println(JSON.toJSON(user));

              }

              /**
               * 用戶分頁,參數(shù)有多個使用下標索引進行處理.如果有兩個參數(shù)(如用戶名和地址):conditionList[0].fieldName=userName、 conditionList[0].fieldName=address
               * 未轉碼請求分頁地址: http://localhost:7011/user/page?conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=周
               * 已轉碼請求分頁地址: http://localhost:7011/user/page?conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=%E5%91%A8
               * @param page
               * @param conditions 條件
               * @return
               */
              @GetMapping("/page")
              public IPage<User> page(Page page, Conditions conditions) {
                  QueryWrapper<User> build = BuildConditionWrapper.build(conditions.getConditionList(), User.class);
                  //通過lambda反射找到User實體類的createTime自動進行排序
                  build.lambda().orderByDesc(User::getCreateTime);
                  return userService.page(page, build);
              }


          }

          16、WebCofig工具類統(tǒng)一處理配置

          • 消息轉換器,中文亂碼,Long的精度長度問題,時間格式等問題
          • cors 跨域支持 可以用@CrossOrigin在controller上單獨設置
          • 統(tǒng)一處理請求URL攔截器
          @Configuration
          @ConditionalOnClass(WebMvcConfigurer.class)
          @Order(Ordered.HIGHEST_PRECEDENCE)
          public class WebConfig implements WebMvcConfigurer {


            @Bean
            public HttpMessageConverters customConverters() {
              //創(chuàng)建fastJson消息轉換器
              FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
              //創(chuàng)建配置類
              FastJsonConfig fastJsonConfig = new FastJsonConfig();
              //修改配置返回內(nèi)容的過濾
              fastJsonConfig.setSerializerFeatures(
                  // 格式化
                  SerializerFeature.PrettyFormat,
                  // 可解決long精度丟失 但會有帶來相應的中文問題
                  //SerializerFeature.BrowserCompatible,
                  // 消除對同一對象循環(huán)引用的問題,默認為false(如果不配置有可能會進入死循環(huán))
                  SerializerFeature.DisableCircularReferenceDetect,
                  // 是否輸出值為null的字段,默認為false
                  SerializerFeature.WriteMapNullValue,
                  // 字符類型字段如果為null,輸出為"",而非null
                  SerializerFeature.WriteNullStringAsEmpty,
                  // List字段如果為null,輸出為[],而非null
                  SerializerFeature.WriteNullListAsEmpty
              );
              // 日期格式
              fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
              // long精度問題
              SerializeConfig serializeConfig = SerializeConfig.globalInstance;
              serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
              serializeConfig.put(Long.class, ToStringSerializer.instance);
              serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
              fastJsonConfig.setSerializeConfig(serializeConfig);
              //處理中文亂碼問題
              List<MediaType> fastMediaTypes = new ArrayList<>();
              fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
              fastJsonConverter.setSupportedMediaTypes(fastMediaTypes);
              fastJsonConverter.setFastJsonConfig(fastJsonConfig);
              //將fastjson添加到視圖消息轉換器列表內(nèi)
              return new HttpMessageConverters(fastJsonConverter);
            }


            /**
             * 攔截器
             */
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
              //registry.addInterceptor(logInterceptor).addPathPatterns("/**");
              //registry.addInterceptor(apiInterceptor).addPathPatterns("/**");
            }

            /**
             * cors 跨域支持 可以用@CrossOrigin在controller上單獨設置
             */
            @Override
            public void addCorsMappings(CorsRegistry registry) {
              registry.addMapping("/**")
                  //設置允許跨域請求的域名
                  .allowedOrigins("*")
                  //設置允許的方法
                  .allowedMethods("*")
                  //設置允許的頭信息
                  .allowedHeaders("*")
                  //是否允許證書 不再默認開啟
                  .allowCredentials(Boolean.TRUE);
            }
          }

          17、運行結果

          • 添加 http://localhost:7011/user/add
          • 分頁 http://localhost:7011/user/page?conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=%E5%91%A8
          • 默認當前current 為1當前第一頁,size為10,當前頁可以顯示10條數(shù)據(jù),也可以根據(jù)自己的情況進行自定義
          • http://localhost:7011/user/page?current=1&size=20&conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=%E5%91%A8

          18、工程代碼與說明

          • 1 、以上問題都是根據(jù)自己學習實際情況進行總結整理,除了技術問題查很多網(wǎng)上資料通過進行學習之后梳理。
          • 2、 在學習過程中也遇到很多困難和疑點,如有問題或誤點,望各位老司機多多指出或者提出建議。本人會采納各種好建議和正確方式不斷完善現(xiàn)況,人在成長過程中的需要優(yōu)質(zhì)的養(yǎng)料
          • 3、 導入代碼的時候遇到最多的問題,我想應該是Maven較多,此時不懂maven的童鞋們可以通過自身情況,進行網(wǎng)上查資料學習。如通過網(wǎng)上找資料長時間解決不了,或者框架有不明白可以通過博客留言,在能力范圍內(nèi)會盡力幫助大家解決問題所在,希望在過程中一起進步,一起成長。
          • 工程代碼在 base 分支 https://github.com/jilongliang/springboot/tree/base

          —————END—————

          推薦閱讀:

          推薦7個牛哄哄 Spring Cloud 實戰(zhàn)項目
          基于 SpringBoot + Vue 框架開發(fā)的網(wǎng)頁版聊天室項目
          基于 SpringBoot + Vue 實現(xiàn)的可視化拖拽編輯的大屏項目
          Github上10個超好看 可視化面板,后臺管理頁面有著落了
          這可能是史上功能最全的Java權限認證框架!

          最近面試BAT,整理一份面試資料Java面試BAT通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構等等。
          獲取方式:關注公眾號并回復 java 領取,更多內(nèi)容陸續(xù)奉上。
          明天見(??ω??)??
          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码无码一区二区三区 | 亚洲a免费视频 | 台湾高清无码视频在线观看 | 久久国语| 伊人大香蕉在线 |