springcloud專案實戰之線上教育網站開發
線上教育
1、專案環境部署
- 專案結構:
- online_parent:根目錄(父工程),管理四個子模組:
- canal_client:canal資料庫表同步模組(統計同步資料)
- common:公共模組父節點
- common_util:工具類模組,所有模組都可以依賴於它
- service_base:service服務的base包,包含service服務的公共配置類,所有service模組依賴於它
- spring_security:認證與授權模組,需要認證授權的service服務依賴於它
- infrastructure:基礎服務模組父節點
- api_gateway:api閘道器服務
- service
- service_edu:教學相關api介面服務
- service_oss:阿里雲oss api介面服務
- service_acl:使用者許可權管理api介面服務(使用者管理、角色管理和許可權管理等)
- service_cms:cms api介面服務
- service_sms:簡訊api介面服務
- service_trade:訂單和支付相關api介面服務
- service_statistics:統計報表api介面服務
- service_ucenter:會員api介面服務
- service_vod:視訊點播api介面服務
Ⅰ、父專案依賴online_parent
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cxd</groupId> <artifactId>online_parent</artifactId> <version>0.0.1-SNAPSHOT</version> <name>online_parent</name> <description>online edu</description> <properties> <java.version>1.8</java.version> <mybatis-plus.version>3.3.1.tmp</mybatis-plus.version> <velocity.version>2.2</velocity.version> <swagger.version>2.7.0</swagger.version> <aliyun.oss.version>3.1.0</aliyun.oss.version> <jodatime.version>2.10.5</jodatime.version> <commons-fileupload.version>1.3.3</commons-fileupload.version> <commons-io.version>2.6</commons-io.version> <commons-lang.version>3.9</commons-lang.version> <httpclient.version>4.5.1</httpclient.version> <jwt.version>0.7.0</jwt.version> <aliyun-java-sdk-core.version>4.5.1</aliyun-java-sdk-core.version> <aliyun-java-sdk-vod.version>2.15.10</aliyun-java-sdk-vod.version> <aliyun-sdk-vod-upload.version>1.4.12</aliyun-sdk-vod-upload.version> <fastjson.version>1.2.28</fastjson.version> <gson.version>2.8.2</gson.version> <json.version>20170516</json.version> <commons-dbutils.version>1.7</commons-dbutils.version> <canal.client.version>1.1.0</canal.client.version> <docker.image.prefix>zx</docker.image.prefix> <alibaba.easyexcel.version>2.1.1</alibaba.easyexcel.version> <apache.xmlbeans.version>3.1.0</apache.xmlbeans.version> </properties> <dependencyManagement> <dependencies> <!--Spring Cloud--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--mybatis-plus 持久層--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- velocity 模板引擎, Mybatis Plus 程式碼生成器需要 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>${velocity.version}</version> </dependency> <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <!--swagger ui--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> <!--aliyunOSS--> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>${aliyun.oss.version}</version> </dependency> <!--日期時間工具--> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${jodatime.version}</version> </dependency> <!--檔案上傳--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>${commons-fileupload.version}</version> </dependency> <!--commons-io--> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons-io.version}</version> </dependency> <!--commons-lang3--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang.version}</version> </dependency> <!--httpclient--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>${httpclient.version}</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jwt.version}</version> </dependency> <!-- aliyun--> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>${aliyun-java-sdk-core.version}</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-vod</artifactId> <version>${aliyun-java-sdk-vod.version}</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.aliyun</groupId>--> <!-- <artifactId>aliyun-sdk-vod-upload</artifactId>--> <!-- <version>${aliyun-sdk-vod-upload.version}</version>--> <!-- </dependency>--> <!-- json--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>${json.version}</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>${gson.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>${alibaba.easyexcel.version}</version> </dependency> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>${apache.xmlbeans.version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Ⅰ-Ⅱ、子工程依賴common
<parent> <artifactId>online_parent</artifactId> <groupId>com.cxd</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>common</artifactId> <packaging>pom</packaging> <modules> <module>service_base</module> </modules> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <!--lombok用來簡化實體類:需要安裝lombok外掛--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> </dependency> <!-- spring boot redis快取引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- lecttuce 快取連線池--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> </dependencies>
Ⅰ-Ⅱ-Ⅰ、子包依賴common_util
<parent>
<artifactId>common</artifactId>
<groupId>com.cxd</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common_util</artifactId>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
Ⅰ-Ⅱ-Ⅱ、子包依賴service_base
<parent>
<artifactId>common</artifactId>
<groupId>com.cxd</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service_base</artifactId>
<dependencies>
<dependency>
<groupId>com.cxd</groupId>
<artifactId>common_util</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
Ⅰ-Ⅲ、子工程依賴service
<parent>
<artifactId>online_parent</artifactId>
<groupId>com.cxd</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service</artifactId>
<packaging>pom</packaging>
<modules>
<module>service_edu</module>
</modules>
<dependencies>
<!--服務容錯-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--服務呼叫-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--服務註冊-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.cxd</groupId>
<artifactId>service_base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- velocity 模板引擎, Mybatis Plus 程式碼生成器需要 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!--日期時間工具-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<!--lombok用來簡化實體類:需要安裝lombok外掛-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Ⅰ-Ⅲ-Ⅰ、子包service_edu
<parent>
<artifactId>service</artifactId>
<groupId>com.cxd</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service_edu</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
</dependency>
</dependencies>
<build>
<!-- 專案打包時會將java目錄中的*.xml檔案也進行打包 -->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
2、edu模組介面開發
- application.yml
server:
port: 8110 # 服務埠
spring:
profiles:
active: dev
application:
name: service_edu # 服務名稱
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver # mysql資料庫連線
url: jdbc:mysql://localhost:3306/db_guli_edu?serverTimezone=GMT%2B8
username: root
data-password: 123456
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
# mybatis日誌
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Ⅰ、mp生成後端程式碼
package com.cxd.service.edu.test;
public class CodeGenerator {
@Test
public void genCode() {
String prefix = "db_guli_";
String moduleName = "edu";
// 1、建立程式碼生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全域性配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("cxd");
gc.setOpen(true); //生成後是否開啟資源管理器
gc.setFileOverride(true); //重新生成時檔案是否覆蓋
gc.setServiceName("%sService"); //去掉Service介面的首字母I
gc.setIdType(IdType.ASSIGN_ID); //主鍵策略
gc.setDateType(DateType.ONLY_DATE);//定義生成的實體類中日期型別
gc.setSwagger2(true);//開啟Swagger2模式
mpg.setGlobalConfig(gc);
// 3、資料來源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/" + prefix + moduleName + "?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(moduleName); //模組名
pc.setParent("com.cxd.service");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);//資料庫表對映到實體的命名
strategy.setTablePrefix(moduleName + "_");//設定表字首不生成
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//資料庫表字段對映
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true)
strategy.setLogicDeleteFieldName("is_deleted");//邏輯刪除欄位名
strategy.setEntityBooleanColumnRemoveIsPrefix(true);//去掉布林值的is_字首
//自動填充
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
strategy.setRestControllerStyle(true); //restful api風格控制器
strategy.setControllerMappingHyphenStyle(true); //url中駝峰轉連字元
mpg.setStrategy(strategy);
//設定BaseEntity
strategy.setSuperEntityClass("BaseEntity");
// 填寫BaseEntity中的公共欄位
strategy.setSuperEntityColumns("id", "gmt_create", "gmt_modified");
// 6、執行
mpg.execute();
}
}
Ⅱ、配置mp分頁外掛
package com.cxd.service.base.config;
@EnableTransactionManagement
@Configuration
@MapperScan("com.cxd.service.*.mapper")
public class MybatisPlusConfig {
/**
* 分頁外掛
* */
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
Ⅲ、配置swagger生成介面文件([http://localhost:8110/swagger-ui.html#!/])
package com.cxd.service.base.config;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket webApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(webApiInfo())
.groupName("webApi")
.select()
.paths(Predicates.and(PathSelectors.regex("/api/.*")))
.build();
}
@Bean
public Docket adminApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(adminApiInfo())
.groupName("adminApi")
.select()
.paths(Predicates.and(PathSelectors.regex("/admin/.*")))
.build();
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("網站的API文件")
.description("api介面定義")
.version("1.0")
// .contact(new Contact("cxd","http://www.qq.com","[email protected]"))
.build();
}
private ApiInfo adminApiInfo(){
return new ApiInfoBuilder()
.title("後臺的API文件")
.description("後臺api介面定義")
.version("1.0")
// .contact(new Contact("cxd","http://www.qq.com","[email protected]"))
.build();
}
}
Ⅳ、編寫BaseEntity類(其他實體類均繼承此類)
package com.cxd.service.base.model;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class BaseEntity implements Serializable {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "講師ID")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
@ApiModelProperty(value = "建立時間", example = "2020-11-11 8:00:00")
@TableField(fill = FieldFill.INSERT)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime gmtCreate;
@ApiModelProperty(value = "更新時間", example = "2020-11-11 8:00:00")
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime gmtModified;
}
Ⅴ、在common包下定義結果返回狀態碼以及統一返回結果
- R.class
@Data
@NoArgsConstructor
@ApiModel("全域性統一返回結果")
public class R {
@ApiModelProperty(value = "是否成功")
private Boolean success;
@ApiModelProperty(value = "返回碼")
private Integer code;
@ApiModelProperty(value = "返回訊息")
private String message;
@ApiModelProperty(value = "返回資料")
private Map<String, Object> data = new HashMap<>();
public static R ok() {
R r = new R();
r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
r.setCode(ResultCodeEnum.SUCCESS.getCode());
r.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return r;
}
public static R error() {
R r = new R();
r.setSuccess(ResultCodeEnum.UNKNOWN_REASON.getSuccess());
r.setCode(ResultCodeEnum.UNKNOWN_REASON.getCode());
r.setMessage(ResultCodeEnum.UNKNOWN_REASON.getMessage());
return r;
}
public static R setResult(ResultCodeEnum resultCodeEnum) {
R r = new R();
r.setSuccess(resultCodeEnum.getSuccess());
r.setCode(resultCodeEnum.getCode());
r.setMessage(resultCodeEnum.getMessage());
return r;
}
public R success(Boolean success) {
this.success(success);
return this;
}
public R message(String message) {
this.setMessage(message);
return this;
}
public R code(Integer code) {
this.setCode(code);
return this;
}
public R data(String key, Object value) {
this.data.put(key, value);
return this;
}
public R data(Map<String, Object> map) {
this.setData(map);
return this;
}
}
- ResultCodeEnum.class
@Getter
@ToString
public enum ResultCodeEnum {
SUCCESS(true, 20000, "成功"),
UNKNOWN_REASON(false, 20001, "未知錯誤"),
BAD_SQL_GRAMMAR(false, 21001, "sql語法錯誤"),
JSON_PARSE_ERROR(false, 21002, "json解析異常"),
PARAM_ERROR(false, 21003, "引數不正確"),
FILE_UPLOAD_ERROR(false, 21004, "檔案上傳錯誤"),
FILE_DELETE_ERROR(false, 21005, "檔案刪除錯誤"),
EXCEL_DATA_IMPORT_ERROR(false, 21006, "Excel資料匯入錯誤"),
VIDEO_UPLOAD_ALIYUN_ERROR(false, 22001, "視訊上傳至阿里雲失敗"),
VIDEO_UPLOAD_TOMCAT_ERROR(false, 22002, "視訊上傳至業務伺服器失敗"),
VIDEO_DELETE_ALIYUN_ERROR(false, 22003, "阿里雲視訊檔案刪除失敗"),
FETCH_VIDEO_UPLOADAUTH_ERROR(false, 22004, "獲取上傳地址和憑證失敗"),
REFRESH_VIDEO_UPLOADAUTH_ERROR(false, 22005, "重新整理上傳地址和憑證失敗"),
FETCH_PLAYAUTH_ERROR(false, 22006, "獲取播放憑證失敗"),
URL_ENCODE_ERROR(false, 23001, "URL編碼失敗"),
ILLEGAL_CALLBACK_REQUEST_ERROR(false, 23002, "非法回撥請求"),
FETCH_ACCESSTOKEN_FAILD(false, 23003, "獲取accessToken失敗"),
FETCH_USERINFO_ERROR(false, 23004, "獲取使用者資訊失敗"),
LOGIN_ERROR(false, 23005, "使用者名稱或密碼不正確"),
COMMENT_EMPTY(false, 24006, "評論內容必須填寫"),
PAY_RUN(false, 25000, "支付中"),
PAY_UNIFIEDORDER_ERROR(false, 25001, "統一下單錯誤"),
PAY_ORDERQUERY_ERROR(false, 25002, "查詢支付結果錯誤"),
ORDER_EXIST_ERROR(false, 25003, "課程已購買"),
GATEWAY_ERROR(false, 26000, "服務不能訪問"),
CODE_ERROR(false, 28000, "驗證碼錯誤"),
LOGIN_DISABLED_ERROR(false, 28002, "該使用者已被禁用"),
REGISTER_MOBLE_ERROR(false, 28003, "手機號已被註冊"),
LOGIN_AUTH(false, 28004, "請先進行登入"),
LOGIN_ACL(false, 28005, "沒有許可權"),
SMS_SEND_ERROR(false, 28006, "簡訊傳送失敗"),
SMS_SEND_ERROR_BUSINESS_LIMIT_CONTROL(false, 28007, "簡訊傳送過於頻繁");
private final Boolean success;
private final Integer code;
private final String message;
ResultCodeEnum(Boolean success, Integer code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
}
Ⅵ、TeacherController實現CRUD
/**
* <p>
* 講師 前端控制器
* </p>
*
* @author cxd
* @since 2020-11-15
*/
@Api(tags = "講師管理")
@RestController
@RequestMapping("admin/edu/teacher")
public class TeacherController {
@Autowired
private TeacherService teacherService;
@ApiOperation(value = "查詢所有老師列表")
@GetMapping("list")
public R listAll() {
List<Teacher> list = teacherService.list();
return R.ok().data("items", list);
}
@ApiOperation(value = "根據ID刪除講師", notes = "根據id刪除,邏輯刪除")
@DeleteMapping("remove/{id}")
public R removeById(@ApiParam("講師ID") @PathVariable String id) {
boolean result = teacherService.removeById(id);
if (result) {
return R.ok().message("刪除成功");
} else {
return R.error().message("教師不存在");
}
}
@ApiOperation("講師分頁列表")
@GetMapping("list/{page}/{limit}")
public R listPage(@ApiParam(value = "當前頁碼", required = true) @PathVariable long page,
@ApiParam(value = "每頁數量", required = true) @PathVariable long limit,
@ApiParam("查詢物件") TeacherQueryVo teacherQueryVo) {
Page<Teacher> pageParam = new Page<>(page, limit);
IPage<Teacher> pageModel = teacherService.selectPage(pageParam, teacherQueryVo);
List<Teacher> records = pageModel.getRecords();
long total = pageModel.getTotal();
return R.ok().data("data", total).data("row", records);
}
@ApiOperation("新增導師")
@PostMapping("save")
public R save(@ApiParam(value = "講師物件", required = true) @RequestBody Teacher teacher) {
boolean result = teacherService.save(teacher);
if (result){
return R.ok().message("儲存成功");
}else{
return R.error().message("操作失敗");
}
}
@ApiOperation("更新導師")
@PutMapping("update")
public R updateById(@ApiParam(value = "講師物件",required = true) @RequestBody Teacher teacher) {
boolean result = teacherService.updateById(teacher);
if (result) {
return R.ok().message("更新成功");
} else {
return R.error().message("資料不存在失敗");
}
}
@ApiOperation("根據id獲取導師資訊")
@GetMapping("get/{id}")
public R getById(@ApiParam(value = "導師物件",required = true) @PathVariable String id) {
Teacher teacher = teacherService.getById(id);
if (teacher != null) {
return R.ok().data("item", teacher);
} else {
return R.error().message("資料不存在");
}
}
Ⅶ、配置logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<property name="log.path" value="./logger/edu"/>
<!--控制檯日誌格式:彩色日誌-->
<!-- magenta:洋紅 -->
<!-- boldMagenta:粗紅-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋紅 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<!--檔案日誌格式-->
<property name="FILE_LOG_PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n"/>
<!--編碼-->
<property name="ENCODING" value="UTF-8"/>
<!--輸出到控制檯-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!--日誌級別-->
<level>INFO</level>
</filter>
<encoder>
<!--日誌格式-->
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!--日誌字符集-->
<charset>${ENCODING}</charset>
</encoder>
</appender>
<!--輸出到檔案-->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日誌過濾器:此日誌檔案只記錄INFO級別的-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${log.path}/log_info.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset>
</encoder>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日誌歸檔路徑以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日誌檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日誌過濾器:此日誌檔案只記錄WARN級別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${log.path}/log_warn.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset> <!-- 此處設定字符集 -->
</encoder>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日誌檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日誌過濾器:此日誌檔案只記錄ERROR級別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${log.path}/log_error.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset> <!-- 此處設定字符集 -->
</encoder>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日誌檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<!--開發環境-->
<springProfile name="dev">
<!--可以靈活設定此處,從而控制日誌的輸出-->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</springProfile>
<!--生產環境-->
<springProfile name="pro">
<root level="ERROR">
<appender-ref ref="ERROR_FILE"/>
</root>
</springProfile>
</configuration>
Ⅷ、service_base包中配置handler
@Component
@Slf4j
public class CommonMetaObjectHandler implements MetaObjectHandler {
@Override
//預設填充欄位
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "gmtCreate", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now());
}
}
Ⅸ、全域性異常處理
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
//全域性異常處理
@ExceptionHandler(Exception.class)
@ResponseBody
public R error(Exception e){
log.error(ExceptionUtils.getMessage(e));
return R.error();
}
//指定異常處理
@ExceptionHandler(BadSqlGrammarException.class)
@ResponseBody
public R error(BadSqlGrammarException e){
log.error(ExceptionUtils.getMessage(e));
return R.setResult(ResultCodeEnum.BAD_SQL_GRAMMAR);
}
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseBody
public R error(HttpMessageNotReadableException e){
log.error(ExceptionUtils.getMessage(e));
return R.setResult(ResultCodeEnum.JSON_PARSE_ERROR);
}
}
Ⅹ、配置logback日誌
- logback-spring.xml(預設日誌的名字,必須是這個名字)
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<property name="log.path" value="D:/project/helen/guli_log/edu" />
<!--控制檯日誌格式:彩色日誌-->
<!-- magenta:洋紅 -->
<!-- boldMagenta:粗紅-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋紅 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<!--檔案日誌格式-->
<property name="FILE_LOG_PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n" />
<!--編碼-->
<property name="ENCODING"
value="UTF-8" />
<!--輸出到控制檯-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!--日誌級別-->
<level>DEBUG</level>
</filter>
<encoder>
<!--日誌格式-->
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!--日誌字符集-->
<charset>${ENCODING}</charset>
</encoder>
</appender>
<!--輸出到檔案-->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日誌過濾器:此日誌檔案只記錄INFO級別的-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${log.path}/log_info.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset>
</encoder>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日誌歸檔路徑以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日誌檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日誌過濾器:此日誌檔案只記錄WARN級別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${log.path}/log_warn.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset> <!-- 此處設定字符集 -->
</encoder>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日誌檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日誌過濾器:此日誌檔案只記錄ERROR級別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${log.path}/log_error.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${ENCODING}</charset> <!-- 此處設定字符集 -->
</encoder>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日誌檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
</appender>
<!--開發環境-->
<springProfile name="dev">
<!--可以靈活設定此處,從而控制日誌的輸出-->
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>
<!--生產環境-->
<springProfile name="pro">
<root level="ERROR">
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>
</configuration>
類上添加註解 @Slf4j
修改異常輸出語句 log.error(e.getMessage());
2-1、edu模組前端開發
- 匯入前端檔案到vscode
1、頁面模組
1、定義路由模組
src/router/index.js
配置講師管理相關路由
2、定義api模組
建立檔案 src/api/teacher.js
// @ 符號在build/webpack.base.conf.js 中配置 表示 'src' 路徑
import request from '@/utils/request'
export default {
list() {
return request({
url: '/admin/edu/teacher/list',
method: 'get'
})
}
}
3、定義頁面元件指令碼
src/views/teacher/list.vue
<script>
import teacherApi from '@/api/teacher'
export default {
// 定義資料模型
data() {
return {
list: [] // 講師列表
}
},
// 頁面渲染成功後獲取資料
created() {
this.fetchData()
},
// 定義方法
methods: {
fetchData() {
// 呼叫api
teacherApi.list().then(response => {
this.list = response.data.items
})
}
}
}
</script>
4、定義頁面元件模板
<!-- 表格 -->
<el-table :data="list" border stripe>
<el-table-column type="index" width="50"/>
<el-table-column prop="name" label="名稱" width="80" />
<el-table-column label="頭銜" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.level === 1" type="success" size="mini">高階講師</el-tag>
<el-tag v-if="scope.row.level === 2" size="mini">首席講師</el-tag>
</template>
</el-table-column>
<el-table-column prop="intro" label="簡介" />
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column prop="joinDate" label="入駐時間" width="160" />
</el-table>
2、分頁查詢
1、定義api模組
src/api/teacher.js
pageList(page, limit, searchObj) {
return request({
url: `/admin/edu/teacher/list/${page}/${limit}`,
method: 'get',
params: searchObj
})
}
2、定義頁面元件指令碼
src/views/teacher/list.vue,完善data定義
data() {// 定義資料
return {
list: null, // 資料列表
total: 0, // 總記錄數
page: 1, // 頁碼
limit: 10, // 每頁記錄數
searchObj: {}// 查詢條件
}
}
修改fetchData方法
fetchData() {
// 呼叫api
teacherApi.pageList(this.page, this.limit, this.searchObj).then(response => {
this.list = response.data.rows
this.total = response.data.total
})
}
3、定義頁面元件模板
在table元件下面新增分頁元件
<!-- 分頁元件 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[5, 10, 20, 30, 40, 50, 100]"
style="padding: 30px 0; text-align: center;"
layout="total, sizes, prev, pager, next, jumper"
/>
4、改變每頁條數
為
@size-change="changePageSize"
定義事件指令碼
// 每頁記錄數改變,size:回撥引數,表示當前選中的“每頁條數”
changePageSize(size) {
this.limit = size
this.fetchData()
}
5、翻頁
為
@current-change="changeCurrentPage"
定義事件指令碼
// 改變頁碼,page:回撥引數,表示當前選中的“頁碼”
changeCurrentPage(page) {
this.page = page
this.fetchData()
},
6、序號列
<el-table-column
label="#"
width="50">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
7、查詢表單
在table元件上面新增查詢表單
<!--查詢表單-->
<el-form :inline="true">
<el-form-item>
<el-input v-model="searchObj.name" placeholder="講師"/>
</el-form-item>
<el-form-item>
<el-select v-model="searchObj.level" clearable placeholder="頭銜">
<el-option value="1" label="高階講師"/>
<el-option value="2" label="首席講師"/>
</el-select>
</el-form-item>
<el-form-item label="入駐時間">
<el-date-picker
v-model="searchObj.joinDateBegin"
placeholder="開始時間"
value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item label="-">
<el-date-picker
v-model="searchObj.joinDateEnd"
placeholder="結束時間"
value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">查詢</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form-item>
</el-form>
重置表單指令碼
// 重置表單
resetData() {
this.searchObj = {}
this.fetchData()
}
3、資料刪除
1、定義api模組
src/api/teacher.js
removeById(id) {
return request({
url: `/admin/edu/teacher/remove/${id}`,
method: 'delete'
})
}
2、定義頁面元件模板
在table元件中新增刪除列
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeById(scope.row.id)">刪除</el-button>
</template>
</el-table-column>
3、定義頁面元件指令碼
// 根據id刪除資料
removeById(id) {
this.$confirm('此操作將永久刪除該記錄, 是否繼續?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return teacherApi.removeById(id)
}).then((response) => {
this.fetchData()
this.$message.success(response.message)
}).catch(error => {
console.log('error', error)
// 當取消時會進入catch語句:error = 'cancel'
// 當後端服務丟擲異常時:error = 'error'
if (error === 'cancel') {
this.$message.info('取消刪除')
}
})
}
4、axios響應攔截器
1、關於code===20000
code!==20000的響應會被攔截,並轉到 error=>{} 處理
if (res.code !== 20000) {
return Promise.reject('error')
}
2、關於response
code===20000時放行,前端頁面接收到response.data的值,而不是response
if (res.code !== 20000) {
return Promise.reject('error')
} else {
return response.data
}
5、新增講師
1、定義api模組
src/api/teacher.js
save(teacher) {
return request({
url: '/admin/edu/teacher/save',
method: 'post',
data: teacher
})
}
2、定義頁面元件指令碼
src/views/teacher/form.vue,完善data定義
<script>
export default {
data() {
return {
// 初始化講師預設資料
teacher: {
sort: 0,
level: 1
},
saveBtnDisabled: false // 儲存按鈕是否禁用,防止表單重複提交
}
}
}
</script>
3、定義頁面元件模板
src/views/teacher/form.vue
<!-- 輸入表單 -->
<el-form label-width="120px">
<el-form-item label="講師名稱">
<el-input v-model="teacher.name" />
</el-form-item>
<el-form-item label="入駐時間">
<el-date-picker v-model="teacher.joinDate" value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item label="講師排序">
<el-input-number v-model="teacher.sort" :min="0"/>
</el-form-item>
<el-form-item label="講師頭銜">
<el-select v-model="teacher.level">
<!--
資料型別一定要和取出的json中的一致,否則沒法回填
因此,這裡value使用動態繫結的值,保證其資料型別是number
-->
<el-option :value="1" label="高階講師"/>
<el-option :value="2" label="首席講師"/>
</el-select>
</el-form-item>
<el-form-item label="講師簡介">
<el-input v-model="teacher.intro"/>
</el-form-item>
<el-form-item label="講師資歷">
<el-input v-model="teacher.career" :rows="10" type="textarea"/>
</el-form-item>
<!-- 講師頭像:TODO -->
<el-form-item>
<el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate()">儲存</el-button>
</el-form-item>
</el-form>
4、實現新增功能
src/views/teacher/form.vue,引入teacher api模組:
import teacherApi from '@/api/teacher'
定義儲存方法
methods: {
saveOrUpdate() {
// 禁用儲存按鈕
this.saveBtnDisabled = true
this.saveData()
},
// 新增講師
saveData() {
// debugger
teacherApi.save(this.teacher).then(response => {
this.$message({
type: 'success',
message: response.message
})
this.$router.push({ path: '/teacher' })
})
}
}
6、顯示講師資訊
1、定義api模組
src/api/teacher.js
getById(id) {
return request({
url: `/admin/edu/teacher/get/${id}`,
method: 'get'
})
}
2、定義頁面元件指令碼
src/views/teacher/form.vue,methods中定義回顯方法
// 根據id查詢記錄
fetchDataById(id) {
teacherApi.getById(id).then(response => {
this.teacher = response.data.item
})
}
頁面渲染成功獲取資料
因為已在路由中定義如下內容:path: 'edit/:id',因此可以使用 this.$route.params.id 獲取路由中的id
//頁面渲染成功
created() {
if (this.$route.params.id) {
this.fetchDataById(this.$route.params.id)
}
}
3、定義頁面元件模板
src/views/teacher/list.vue,表格“操作”列中增加“修改”按鈕
<router-link :to="'/teacher/edit/'+scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">修改</el-button>
</router-link>
7、更新講師
1、定義api模組
src/api/teacher.js
updateById(teacher) {
return request({
url: '/admin/edu/teacher/update',
method: 'put',
data: teacher
})
}
2、定義頁面元件指令碼
src/views/teacher/form.vue,methods中定義updateData
// 根據id更新記錄
updateData() {
// teacher資料的獲取
teacherApi.updateById(this.teacher).then(response => {
this.$message({
type: 'success',
message: response.message
})
this.$router.push({ path: '/teacher' })
})
},
完善saveOrUpdate方法
saveOrUpdate() {
// 禁用儲存按鈕
this.saveBtnDisabled = true
if (!this.teacher.id) {
this.saveData()
} else {
this.updateData()
}
}
8、元件重用問題
問題:vue-router導航切換 時,如果兩個路由都渲染同個元件,
元件的生命週期方法(created或者mounted)不會再被呼叫, 元件會被重用,顯示上一個路由渲染出來的自建
解決方案:可以簡單的在 router-view上加上一個唯一的key,來保證路由切換時都會重新觸發生命週期方法,確保元件被重新初始化。
修改 src/views/layout/components/AppMain.vue 檔案如下:
<router-view :key="key"></router-view>
computed: {
key() {
return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date()
}
}