我不能停滯不前
前言
諸君,搭建個人博客系列缭受,我終于開始更了胁澳。。沒想到還有人催更米者,受寵若驚韭畸!
在閱讀本文前,我假設(shè)您除了Spring Boot蔓搞,還對以下技術(shù)有了解
- ORM框架:Mybatis-Plus
- 插件工具:Lomok
- 數(shù)據(jù)庫連接池:Druid
- 模板引擎:Freemark胰丁,Thymeleaf
- API文檔框架:Swagger
為了用戶體驗,正文部分是一氣呵成的喂分,搭建過程中所遇問題隘马,可以看踩坑紀部分。
提醒一下:
若是您要參考正文部分來搭建環(huán)境妻顶,請務(wù)必看踩坑紀部分酸员,否則只看正文部分葱她,不便于理解且可能項目會跑不起來偷线。
好吧。游岳。其實這里本來還有一些話的沥潭,但是發(fā)現(xiàn)寫的太長了邀泉。。也是為了不影響讀者體驗钝鸽,放在了后記中汇恤;畢竟各位是來看技術(shù)文章的,不是看我瞎BB的拔恰,不能主次顛倒因谎。
開始正文
正文
1. 數(shù)據(jù)庫設(shè)計
數(shù)據(jù)庫設(shè)計是最初的階段,同時我也是卡在這階段最久颜懊。至于為什么卡這么久請看踩坑紀部分
根據(jù)我上一篇的【Spring Boot】搭建個人博客 - 需求分析設(shè)計數(shù)據(jù)庫表财岔。
數(shù)據(jù)庫設(shè)計規(guī)范主要參考阿里巴巴Java開發(fā)手冊 1.4.0风皿,以及一些網(wǎng)上資料;
表名前綴是模塊名匠璧,分了8個模塊桐款。
一共18張表,其中16張實體表夷恍,2張多對多關(guān)系表魔眨;
sql文件會與項目一同上傳至Github
2. idea創(chuàng)建Spring boot項目
具體創(chuàng)建過程參考這里:【Spring Boot】初體驗
給出application.properties和pom.xml
application.properties
#上下文
server.servlet.context-path=/blog
#日志配置
logging.level.org.springframework.web=DEBUG
#Thymeleaf 配置
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
##緩存設(shè)置為false, 這樣修改之后馬上生效,便于調(diào)試酿雪;生產(chǎn)環(huán)境下可以設(shè)置為true
spring.thymeleaf.cache=false
#Druid配置
##JDBC配置
spring.datasource.druid.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&useSSL=false&characterEncoding=utf8
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.username=root
spring.datasource.druid.password=root
##連接池配置
spring.datasource.druid.max-active=20
#Freemarker配置
##不使用文件系統(tǒng)優(yōu)先冰沙,而使用classpath下的資源文件優(yōu)先,解決打jar包運行后执虹,出現(xiàn)的異常問題
spring.freemarker.prefer-file-system-access=false
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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">
<modelVersion>4.0.0</modelVersion>
<groupId>top.sinch</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>blog</name>
<description>Blog project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring Boot 熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--MyBatis Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!--MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--Swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--Lomok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!--Gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!--Freemarker模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--Thymeleaf模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-->Thymeleaf的非嚴格HTML格式包-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Mybatis-Plus代碼生成器生成模板代碼
使用Mybatis-Plus官方提供的代碼生成器Demo生成模板代碼拓挥。
需要注意的是:
- 生成器根據(jù)數(shù)據(jù)庫表名,一次生成的是同一模塊下代碼袋励;若有幾個模塊則需要更改模塊名及相對應(yīng)表名侥啤;有幾個模塊,執(zhí)行幾次生成器生成對應(yīng)模塊下的代碼
- 若只有一個模塊或者不區(qū)分模塊茬故,則只用執(zhí)行一次生成器
新建包路徑
在src\main\java
下新建包路徑com.baomidou.mybatisplus
盖灸,把代碼生成器和項目代碼區(qū)分開
代碼生成器(把官方Demo根據(jù)需求改造了一下)
package com.baomidou.mybatisplus;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
/**
* mybatis-plus 代碼生成器
*
* @Author sincH
* @Date 2018/11/10
*/
public class CodeGenerator {
public static void main(String[] args) {
// 代碼生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
//項目根目錄
String projectPath = "D:/_Code/idea/blog";
// String projectPath = "C:/Users/sincH/Desktop/Temp/blog";
//Java源碼輸出目錄
gc.setOutputDir(projectPath + "/src/main/java");
//作者
gc.setAuthor("sincH");
//是否打開輸出目錄,默認true
gc.setOpen(false);
//開啟swagger2模式(將實體類默認的Javadoc文檔注解轉(zhuǎn)為Swagger文檔注解)磺芭,默認false
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
// 數(shù)據(jù)源配置
DataSourceConfig dsc = new DataSourceConfig();
//數(shù)據(jù)庫連接URL
dsc.setUrl("jdbc:mysql://localhost:3306/blog?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");//數(shù)據(jù)庫模式赁炎;MySQL中庫即模式
//數(shù)據(jù)庫驅(qū)動
dsc.setDriverName("com.mysql.jdbc.Driver");
//數(shù)據(jù)庫用戶名
dsc.setUsername("root");
//數(shù)據(jù)庫密碼
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
//模塊名
pc.setModuleName("article");
//父包名;模塊將在父包下生成
pc.setParent("top.sinch.blog");
mpg.setPackageInfo(pc);
// 自定義配置
// InjectionConfig cfg = new InjectionConfig() {
// @Override
// public void initMap() {
// // to do nothing
// }
// };
// List<FileOutConfig> focList = new ArrayList<>();
// focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
// @Override
// public String outputFile(TableInfo tableInfo) {
// // 自定義輸入文件名稱
// return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
// + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
// }
// });
// cfg.setFileOutConfigList(focList);
// mpg.setCfg(cfg);
//setXml(null)代表不生成xml文件
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//表名下劃線轉(zhuǎn)駝峰
strategy.setNaming(NamingStrategy.underline_to_camel);
//列名下劃線轉(zhuǎn)駝峰
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//Boolean類型字段是否移除is前綴(默認 false)
strategy.setEntityBooleanColumnRemoveIsPrefix(true);
// strategy.setSuperEntityClass("com.baomidou.ant.common.BaseEntity");
//是否開啟實體類Lombok模式(默認false)
strategy.setEntityLombokModel(true);
//是否開啟RestController風(fēng)格
strategy.setRestControllerStyle(true);
// strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
//表名(數(shù)據(jù)庫中存在的表);多表傳數(shù)組
strategy.setInclude(new String[]{
"article_info","article_content","article_comment","article_comment_reply",
"article_archive","article_label","article_category",
"r_article_info_article_label","r_article_info_article_category"
});
// strategy.setSuperEntityColumns("id");
//駝峰轉(zhuǎn)連字符(是否開啟Controller映射連字符風(fēng)格)
strategy.setControllerMappingHyphenStyle(true);
/**
*設(shè)置表名前綴钾腺;
*此表名前綴若與數(shù)據(jù)庫表名前綴一致徙垫,則自動創(chuàng)建實體類時,實體類名匹配數(shù)據(jù)庫表名下劃線后面的名放棒;
*栗子:數(shù)據(jù)庫表名為 admin_info 姻报,當(dāng)strategy.setTablePrefix("admin_")時,則實體類名為Info间螟;
*若不設(shè)置表名前綴吴旋,則實體類名匹配數(shù)據(jù)庫表名
*/
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
//設(shè)置代碼生成器的模板引擎
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
//執(zhí)行代碼生成器
mpg.execute();
}
}
需要注意的是:
把代碼生成器生成的代碼輸出目錄設(shè)置為項目地址,這樣就可以不用在代碼生成后還要手動復(fù)制到項目中厢破。
生成器生成結(jié)果及其對應(yīng)模塊
這里是9個模塊荣瑟,多了一個core(核心)模塊;是放項目的配置類摩泪,攔截器笆焰,過濾器等等,其實也可以不用建加勤;不建的話仙辟,配置類那些比較散亂分布,我覺得還是集中比較好鳄梅,就建了個core包
修改生成器生成的模板代碼命名
有時候叠国,模板代碼的命名不太符合需求,比如我這里statistics(統(tǒng)計)模塊下有個統(tǒng)計IP的子模塊戴尸,模板代碼用了駝峰命名把IP命名為Ip粟焊,我覺得還是都用大寫字母表示IP好
4. 單元測試
基于以上,若是單模塊項目或者多模塊項目無同名Class的話孙蒙,項目的后端環(huán)境搭建就基本到此完成了项棠,寫個單元測試;不會寫單元測試的請參考嘟嘟獨立博客的這篇文章:Spring Boot干貨系列:(十二)Spring Boot使用單元測試挎峦。
新建包路徑
在test
文件下新建要進行單元測試的類的相對應(yīng)包路徑香追;
這里舉例,要進行單元測試的類是ContentMapper
ContentMapper單元測試
package top.sinch.blog.article.mapper;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import top.sinch.blog.BlogApplication;
import top.sinch.blog.article.entity.Content;
import javax.annotation.Resource;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class ContentMapperTest {
// @Autowired(required = false)//允許依賴對象為null
@Resource
private ContentMapper contentMapper;
@Test
public void insert() {
Content content = new Content();
content.setDetail("23333333333333333333333333333333");
// content.setArticleInfoId(Integer.toUnsignedLong(1));
int result = contentMapper.insert(content);
Assert.assertThat(result, equalTo(1 ));
}
}
單元測試結(jié)果
test passed:測試通過
但是請注意坦胶,我這里強調(diào)的是單模塊項目或者多模塊項目無同名Class透典,而我的這個個人博客項目是多模塊且不同模塊下有同名Class的,所以您會發(fā)現(xiàn)單元測試會失敗顿苇,報以下錯誤或者類似錯誤
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [top.sinch.blog.BlogApplication]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'infoController' for bean class [top.sinch.blog.admin.controller.InfoController] conflicts with existing, non-compatible bean definition of same name and class [top.sinch.blog.about.controller.InfoController]
這個坑我就不放在踩坑紀部分說了峭咒,在這里解釋;
出現(xiàn)這個錯誤的原因:
是因為本項目中不同模塊下都有一個Info實體類纪岁,相對應(yīng)的就都有InfoController凑队,InfoServiceImpl,InfoMapper幔翰;若不為不同模塊下的InfoController漩氨,InfoServiceImpl,InfoMapper取別名的話遗增,這些InfoController等在注冊進Spring容器時就會失敳挪ぁ;因為Spring默認是用類名進行Bean注冊的贡定,而它們類名又都是InfoController等赋访,自然會失敗
這里舉例about模塊和admin模塊,以便于理解
解決方法
為不同模塊下的InfoController缓待,InfoServiceImpl蚓耽,InfoMapper取別名;
同樣舉例旋炒,about模塊和admin模塊步悠。
然后再進行單元測試,完美通過瘫镇!Perfect6κ蕖答姥!
5. 設(shè)計RESTful API
初次嘗試在項目中設(shè)計RESTful API;這里鑒于篇幅原因谚咬,僅給出一個Demo鹦付,其余都是類似的;不過在Demo之前先講講RESTful API設(shè)計規(guī)范择卦,規(guī)范主要參考阮一峰的這篇RESTful API 最佳實踐
RESTful API 設(shè)計規(guī)范
阮一峰的RESTful API 最佳實踐推薦使用復(fù)數(shù)URL敲长,但是我根據(jù)項目情況并沒有采用復(fù)數(shù)URL;
這里以article模塊下的InfoController為例子
-
GET /article/info/{id}
獲取單個文章信息 -
GET /article/info/all
獲取所有文章信息 -
POST /article/info
新增一篇文章信息 -
PUT /article/info
更新一篇文章信息 -
DELETE /article/info/{id}
刪除一篇文章信息
swagger2配置類
package top.sinch.blog.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger2配置類
*
* @Author sincH
* @Date 2018/11/14
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("top.sinch.blog"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("sincH個人博客RESTful APIs")
.description("sincH個人博客API文檔")
.contact(new Contact("sincH","http://www.reibang.com/u/64e4e9db42c9","923395273@qq.com"))
.version("1.0")
.build();
}
}
article模塊下的InfoController
package top.sinch.blog.article.controller;
import com.google.gson.Gson;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import top.sinch.blog.article.entity.Info;
/**
* <p>
* 前端控制器 文章信息
* </p>
*
* @author sincH
* @since 2018-11-20
*/
@RestController("articleInfoController")
@RequestMapping("/article/info")
public class InfoController {
@ApiOperation("獲取單個文章信息")
@GetMapping("/{id}")
public String get(@PathVariable("id") String id) {
Info articleInfo = new Info();
articleInfo.setAuthor("sincH");
articleInfo.setTitle("Test");
return new Gson().toJson(articleInfo);
}
@ApiOperation("獲取所有文章信息")
@GetMapping("/all")
public String list(){
return "list successful";
}
@ApiOperation("新增一篇文章信息")
@PostMapping("")
public String save(){
return "save successful";
}
@ApiOperation("更新一篇文章信息")
@PutMapping("")
public String update(){
return "update successful";
}
@ApiOperation("刪除一篇文章信息")
@DeleteMapping("/{id}")
public String remove(@PathVariable("id") String id){
return "remove successful";
}
}
除了以上步驟外秉继,肯定要先導(dǎo)入swagger相關(guān)依賴包祈噪;
有認真看的看官,應(yīng)該知道我已經(jīng)先在pom.xml中導(dǎo)入了swagger相關(guān)依賴包
所以設(shè)計完RESTful API尚辑,直接在瀏覽器輸入地址:
http://localhost:8080/blog/swagger-ui.html
若您更改了端口和項目名辑鲤,請相對應(yīng)更改地址;不然肯定訪問不了(感覺說這話有點多余)
對某個RESTful API進行測試
踩坑紀
紀一 :命名規(guī)范問題
命名規(guī)范是我這么久都沒更新文章的主要原因杠茬;我因為命名問題卡在了數(shù)據(jù)庫設(shè)計階段超級久遂填;每天上班前的一小時,下班后的兩小時都在想數(shù)據(jù)庫表名澈蝙,字段名吓坚,類名等怎么命名會對后面的開發(fā)比較友好;
沒錯灯荧!您也不用懷疑礁击;就是命名問題卡了我許久,也不是什么技術(shù)大問題逗载;因為我對命名有些許強迫癥哆窿,命名不好就會推翻重來;不過倘若是別人一開始就設(shè)計好的命名厉斟,我其實也不會太糾結(jié)挚躯。關(guān)鍵這是我自己設(shè)計的就會十分糾結(jié)。
光是最初的數(shù)據(jù)庫表名設(shè)計擦秽,我就有好幾種命名码荔;
以文章信息表為例,有以下命名
- article
- article_base
- article_article_info
- article_info
命名規(guī)范參考了阿里巴巴Java開發(fā)手冊 1.4.0感挥,以及一些網(wǎng)上資料缩搅;
接下來逐個分析為什么我使用這個命名,以及為什么拋棄這個命名触幼;可能比較長硼瓣,希望您有耐心看;可能有些人覺得沒必要這么糾結(jié)命名置谦,那么您可以跳過這一紀堂鲤,看下一個坑的紀錄亿傅。
-
article
- 為什么使用這個命名
article這命名其實不用過多解釋,當(dāng)你想設(shè)計文章表時瘟栖,那么article肯定是你的首選命名葵擎,可能您看到過essay這個命名,當(dāng)然也是可以的慢宗,但是推薦使用article - 為什么拋棄這個命名
根據(jù)阿里巴巴Java開發(fā)手冊 1.4.0中的MySQL數(shù)據(jù)庫(一)建表規(guī)約第8條
- 【強制】varchar 是可變長字符串坪蚁,不預(yù)先分配存儲空間奔穿,長度不要超過5000镜沽,如果存儲長度大于此值,定義字段類型為 text贱田,獨立出來一張表缅茉,用主鍵來對應(yīng),避免影響其它字段索引效率男摧。
那么article(文章)表中肯定有個content(內(nèi)容)字段蔬墩,而content字段長度不確定,有可能會超過5000耗拓,所以我決定將content獨立成表拇颅,命名為article_content;
那么article乔询,article_content不太統(tǒng)一樟插,要么都是“XXX_XXX”格式,要么就都不是比較好竿刁;而且根據(jù)阿里巴巴Java開發(fā)手冊 1.4.0中的MySQL數(shù)據(jù)庫(一)建表規(guī)約第10條- 【推薦】表的命名最好是加上“業(yè)務(wù)名稱_表的作用”黄锤。 正例:alipay_task / force_project / trade_config
因此將article重命名為article_base
- 為什么使用這個命名
-
article_base
- 為什么使用這個命名
因為拋棄了article命名,所以就改成了article_base食拜;可能有人會說為什么不用article_info呢鸵熟,因為我覺得文章表直接命名article就行了,如果命名article_info有點多此一舉负甸,但是又要分表流强,所以就想到了article_base,直譯為文章基礎(chǔ)表呻待,以后要是想擴展表煮盼,可以命名為article_extra之類的,妙啊 - 為什么拋棄這個命名
因為使用MyBatis-Plus的代碼生成器時带污,倘若設(shè)置了表名前綴且表名前綴與數(shù)據(jù)庫表名前綴一致僵控,那么代碼生成器生成的實體類名為表名前綴后的名。
舉個栗子:
也就是說倘若代碼生成器里設(shè)置了表名前綴為"article_"鱼冀,而數(shù)據(jù)庫表名為"article_base"报破,則實際由代碼生成器生成的實體類名為Base悠就。
那么實體類名為Base,不如Info來得更直觀友好充易,因此拋棄article_base命名
- 為什么使用這個命名
//省略前面的配置
//模塊名
pc.setModuleName("article");
//省略中間的配置
//表名(數(shù)據(jù)庫中存在的表);多表傳數(shù)組
strategy.setInclude(new String[]{
"article_base"
});
/**
*設(shè)置表名前綴梗脾;
*此表名前綴若與數(shù)據(jù)庫表名前綴一致,則自動創(chuàng)建實體類時盹靴,實體類名匹配數(shù)據(jù)庫表名前綴后面的名炸茧;
*栗子:數(shù)據(jù)庫表名為 article_base ,當(dāng)strategy.setTablePrefix("article_")時稿静,則實體類名為Base梭冠;
*若不設(shè)置表名前綴,則實體類名匹配數(shù)據(jù)庫表名
*/
strategy.setTablePrefix(pc.getModuleName() + "_");
-
article_article_info
- 為什么使用這個命名
前面分析article_base這個命名時說到了改备,代碼生成器的表名前綴若與數(shù)據(jù)庫的表名前綴一致時控漠,則生成的實體類名為表名前綴后的名;
也就是說代碼生成器的表名前綴為"article_"悬钳,數(shù)據(jù)庫表名為"article_info"盐捷,則實際由代碼生成器生成的實體類名為Info。而單單Info這個名并不夠直觀默勾,我希望它是ArticleInfo碉渡,因此article_info前面再加了article,這樣命名就是article_article_info母剥,然后代碼生成器生成的實體類名就是ArticleInfo滞诺,不過這樣看著就很重復(fù)了。 - 為什么拋棄這個命名
拋棄的原因很簡單媳搪,因為article_article_info這樣的命名看著很重復(fù)铭段,很不舒服,心里難受秦爆,就拋棄了序愚。。
- 為什么使用這個命名
-
article_info
- 為什么最終使用這個命名
使用這個命名的原因也很簡單等限,在拋棄了article爸吮,article_base,article_article_info這幾個命名后望门,權(quán)衡利弊形娇,綜合考慮,還是覺得article_info這個命名好
- 為什么最終使用這個命名
命名規(guī)范這個坑我寫得還挺長筹误,我覺得能看完命名規(guī)范這個坑的都是勇者桐早,我為你們鼓掌,畢竟看我在命名規(guī)范這里瞎BB也不容易。
紀二:數(shù)據(jù)庫建立索引
在搞定命名規(guī)范問題后哄酝,又要面對索引問題友存。
在進行數(shù)次網(wǎng)上沖浪后,對怎么建立索引進行了簡單總結(jié)陶衅。
- 【推薦】對出現(xiàn)在SQL語句的
WHERE
后面的字段建立索引 - 【推薦】對需要精確查詢("=","IN"和"<=>"查詢)的字段建立HASH索引
- 【推薦】對需要范圍查詢的字段建立BTREE索引
好屡立!總結(jié)完畢!可能有些人覺得太簡單了搀军,的確膨俐,相對于其他關(guān)于索引的文章,我總結(jié)的是很簡單罩句,所以僅僅只能適用于簡單的情況焚刺,至于什么是簡單的情況,請各位自己思考的止;
關(guān)于我參考的網(wǎng)上沖浪資料在文末的參考文章給出
紀三:模型同步到數(shù)據(jù)庫中出現(xiàn)問題
在Navicat Premuim中設(shè)計模型后同步到數(shù)據(jù)庫中出現(xiàn)問題
分析
因為我在某些字段上加了HASH(哈希)索引檩坚,而HASH索引是不支持排序的着撩;而從模型同步到數(shù)據(jù)庫時诅福,建立了索引的字段默認用了ASC排序(升序排列),就算你建立索引時不設(shè)置排序方式拖叙,同步時也會默認用ASC排序氓润,這有點坑。薯鳍。而HASH索引不支持排序咖气,自然同步會失敗。
-
模型中并沒有設(shè)置排序方式
排序方式 -
將模型導(dǎo)出為SQL文件挖滤,發(fā)現(xiàn)默認用了ASC排序
ASC排序
解決方法
將模型導(dǎo)出為SQL文件崩溪,再將SQL文件中的ASC去除,最后在Navicat Premium中運行SQL文件斩松,完美解決伶唯!
后記
。惧盹。終于乳幸,我!寫到了后記钧椰;實不相瞞粹断,這篇文章,我也寫了好久嫡霞,期間歷經(jīng)修修改改瓶埋,推翻重來之類的。下面就是我瞎BB的時間了;it's my show time!!
Q:別人的項目后端環(huán)境都搭建很快的养筒,為什么你用了這么久=坪骸!
A:你也說是別人了闽颇,我就是我盾戴,是與眾不同的我;好吧兵多,開玩笑的尖啡,主要是兩點原因;
其一:命名規(guī)范問題剩膘;沒錯衅斩,就是我在踩坑紀中也提到的命名規(guī)范問題。以前我搭建項目后端環(huán)境也是很快的怠褐,好吧畏梆。不過,那時我并沒有考慮太多命名規(guī)范什么的奈懒,導(dǎo)致我后面再看自己的代碼時奠涌,就覺得 這是誰寫的代碼,什么鬼傲仔印溜畅!
其二:數(shù)據(jù)庫索引;沒錯极祸,同樣是在踩坑紀中也提到的索引問題慈格;呀,怎么去建立索引遥金,我也思考了好久浴捆。
以上便是我后端環(huán)境搭建這么久的原因。其實并不是什么技術(shù)上的大問題Q:就算是那兩點原因稿械,那也不用久啊选泻,從你項目需求分析開始,到現(xiàn)在兩個多月了都溜哮,黃花菜都涼了滔金。
A:行的吧,的確也是不用那么久茂嗓。還有原因就是我在實習(xí)餐茵。∈鑫可能你想說這不是理由忿族,好吧锣笨,不是就不是,但我也利用了每天上班前的一小時道批,下班后的兩小時在做這個項目了错英。我在努力了,為什么還是這么慢呢隆豹,究其原因椭岩,我還是知道的,就是目前的我還是太弱雞了璃赡,不夠強啊判哥。嗯,我不能停滯不前碉考。
再有就是時不時懶癌發(fā)作塌计。。就沒有然后了
綜上侯谁,弱雞+間歇性懶癌發(fā)作=久Q:拖了這么久锌仅,對甲方爸爸有沒有什么影響?
A:獨秀同學(xué)墙贱,請你坐下热芹,一看你就沒認真看我的文章,我這是個人博客項目嫩痰,甲方爸爸不是其他人剿吻,就是我自己窍箍,至于對我有沒有影響串纺,請看下一個QA部分。
如果硬要說甲方爸爸是其他人的話椰棘,那這個其他人就是關(guān)注我這個博客項目的人纺棺;我看到評論區(qū)有人催更的時候,真是有點受寵若驚邪狞。
當(dāng)然要是有真.甲方爸爸或者是商業(yè)項目的話祷蝌,我肯定不會拖這么久了。要是真拖這么久的話帆卓,你這是在玩火啊巨朦,少年Q:拖了這么久,對你有沒有什么影響剑令?
A:一開始我以為不會有什么影響糊啡,直到開始寫這篇文章時,才意識到影響太大了吁津。
消極影響:開始寫這篇文章時棚蓄,肯定要梳理一下思路,然后我就發(fā)現(xiàn)隔了太久了,有些思路就不知道是怎么回事了梭依;有些bug稍算,踩過的坑也因為太久了就忘記了;雖然平時在遇到bug時役拴,會進行速記糊探,但時間久了,就不知道這速記記的是什么鬼河闰。所以影響真的是很大侧到,我以后應(yīng)該不會拖這么久了。
積極影響:說實話淤击,我自己也沒想到讓我卡殼這么久的并不是什么技術(shù)大問題匠抗,而是命名之類的設(shè)計問題。
突然想起很久之前污抬,一位已經(jīng)在外工作的師兄說的一句話汞贸,你不能僅僅是Coder,還要是Designer印机;感覺自己已經(jīng)朝著Designer往前了一步
終于矢腻。∩淙快要寫完了多柑,這篇文章寫得真是又長又久,能看到這里的楣责,我真心覺得你牛逼
最后說一句竣灌,因為文章我寫的又長又久,也不想回頭校對秆麸,所以要是文章中有出錯的地方或者您有其他意見初嘹,請在評論區(qū)中賜教
參考文章
因為隔了太久了,而且這次參考的很多沮趣,有些參考文章就忘記收藏了屯烦,下面給出我收藏記的:
阿里巴巴Java開發(fā)手冊 1.4.0
MySQL命名、設(shè)計及使用規(guī)范
數(shù)據(jù)庫設(shè)計中的命名規(guī)范
字段類型與合理的選擇字段類型
MySQL索引類型 btree索引和hash索引的區(qū)別
Mybatis-Plus代碼生成器
Spring Boot干貨系列:(十二)Spring Boot使用單元測試
Spring Boot中使用Swagger2構(gòu)建強大的RESTful API文檔
RESTful API 最佳實踐
項目地址
Github:h-blog
小結(jié)
最后做個小結(jié)吧房铭。驻龟。本來不用做的。拖得太久了缸匪。翁狐。我也很絕望啊
希望自己能吸取這次教訓(xùn)吧,下次不要拖這么久了豪嗽。
再再說一次谴蔑,要是文中有錯誤或者有其他意見豌骏,請私信我或者評論區(qū)留言