記事ディレクトリ
1. プロジェクトを作成する
1. 新しい Maven プロジェクトを作成する
開いているプロジェクトがない場合は、直接[新しいプロジェクト]をクリックします。他のプロジェクトがすでに開いている場合は、順番に をクリックし、 [次へ]File -> New -> Project -> Maven
をクリックして、新しい Maven プロジェクトを作成します (ここではプロジェクト SDK バージョン 1.8 を使用しています)
次に、Maven プロジェクトを次のように構成します (具体的な意味はご自身で見つけてください)
- 名前、プロジェクト名
- Location、プロジェクトのローカル ストレージ パス
- GroupId、Maven グループは通常、Web サイトでは逆さまに書かれていますが、cn.zhangsan のように自分で名前を付けることもできます
- ArtifactId、グループ内のモジュールの名前
- Version、Maven プロジェクトのバージョン番号
「Finnish」をクリックした後(他のプロジェクトが開いている場合は、「プロジェクトを開く」ウィンドウが表示されます。「このウィンドウ」を選択すると、現在のプロジェクトが閉じて、作成したプロジェクトが開きます。「新しいウィンドウ」を選択すると、作成したプロジェクトが新しいウィンドウで開きます)。プロジェクトが作成されます
2. SpringBootをビルドする
SpringBoot の使用は非常に簡単で、 pom.xmlに SpringBoot の依存関係を追加するだけで、最終的な結果は次のようになります。
- parent、 SpringBoot を現在のプロジェクトの親として設定します。つまり、プロジェクトは SpringBoot を継承します。
- プロパティ では、バージョン管理を容易にするために、通常、ここに依存関係のバージョン番号を書き込み、そのすぐ下に引用します。
- 依存関係、依存関係リスト
- 依存関係、 依存関係
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
</parent>
<groupId>com.jl15988</groupId>
<artifactId>we-shopping</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
Maven の依存関係をロードするには、右上隅にある小さなアイコンをクリックして依存関係をプロジェクトに導入する必要があります。
3. インターフェースの作成
以下にsrc\main\java
新しいパッケージを作成しcom.jl15988.shopping
(パッケージ名はグループ名、またはグループ名 + モジュール名と同じであることがよくありますが、大文字にすることはできません)、次にクラス (ここではプロジェクト名 + アプリケーションを使用して名前を付けています) を作成しWeShoppingApplication
、次のコード
package com.jl15988.shopping;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Jalon
* @since 2023/8/1 10:56
**/
@SpringBootApplication
public class WeShoppingApplication {
public static void main(String[] args) {
SpringApplication.run(WeShoppingApplication.class);
}
}
com.jl15988.shopping
次に、controller
パッケージを作成し、コントローラー パッケージの下にクラスを作成しHelloController
、次のコードを追加します。
- @RestController、アノテーション。現在のコントローラー クラスが次であることを示すために使用されます。
- @GetMapping、このメソッドが
Get
リクエストであることを宣言します
package com.jl15988.shopping.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Jalon
* @since 2023/8/1 10:59
**/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}
}
次に、プロジェクトを開始します。WeShoppingApplication
緑色の三角形を直接クリックしてプロジェクトを開始できます (プロジェクトを開始している場合は、右上隅にある小さな緑色の三角形を直接クリックできます)
次に、ブラウザは localhost:8080/hello にアクセスし、レンダリングは次のようになります (他のプロジェクトまたはプログラムがポート 8080 を占有している場合、エラーが報告される可能性があります)。
2. 開発インターフェース
1. データベースの作成
navicatを使用してデータベースを作成するwe_shopping
次にSQL文を実行してデータテーブルを作成します。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`username` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`nick` varchar(26) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
`update_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
2. コード生成ツールを追加する
まずプロジェクトに依存関係を導入します
<!-- 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 代码生成 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 代码生成引擎模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>3.1.0</version>
</dependency>
com.jl15988.shopping
次に、CodeGenerator
その下にクラスを作成し、次の内容を追加します
package com.jl15988.shopping;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import java.sql.Types;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Jalon
* @since 2023/8/1 11:35
**/
public class CodeGenerator {
// 数据库地址
private static final String URL = "jdbc:mysql://localhost:3306/we_shopping?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
// 数据库用户名
private static final String USERNAME = "root";
// 数据库密码
private static final String PASSWORD = "123456";
// 生成代码的包名
private static final String PACKAGE = "com.jl15988.shopping";
// 作者
private static final String AUTHOR = "Jalon";
// 过滤的数据库名前缀
private static final String[] PREFIXS = {
"sys_"};
public static void main(String[] args) {
String projectPath = System.getProperty("user.dir");
FastAutoGenerator.create(URL, USERNAME, PASSWORD)
.globalConfig(builder -> {
builder.author(AUTHOR) // 设置作者
// .enableSwagger() // 开启 swagger 模式
.outputDir(projectPath + "/src/main/java") // 输出目录
.disableOpenDir(); //
})
.dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
// 自定义类型转换
return DbColumnType.INTEGER;
}
return typeRegistry.getColumnType(metaInfo);
}))
.packageConfig(builder -> {
builder.parent(PACKAGE) // 设置父包名
// .moduleName("") // 设置父包模块名
.entity("domain.entity")
.pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
})
.strategyConfig((scanner, builder) -> {
List<String> tables = getTables(scanner.apply("请输入表名,多个英文逗号分隔,所有表生成输入 all"));
builder.addTablePrefix(PREFIXS) // 过滤前缀
.addInclude(tables) // 增加表匹配
// controller配置
.controllerBuilder()
.enableRestStyle() // 添加@RestController
.enableHyphenStyle() // 驼峰转连字符
// 实体类配置
.entityBuilder()
.enableFileOverride() // 生成覆盖
.enableLombok() //添加lombok
.addTableFills(new Column("create_time", FieldFill.INSERT))
.disableSerialVersionUID() // 禁用生成 serialVersionUID
.idType(IdType.ASSIGN_ID) // 当用户未输入时,采用雪花算法生成一个适用于分布式环境的全局唯一主键
.build();
})
// 引擎模板,默认的是Velocity引擎模板
// .templateEngine(new BeetlTemplateEngine()) // Beetl引擎模板
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板
.execute();
}
// 处理 all 情况
protected static List<String> getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
}
次に、小さな緑色の三角形をクリックしてこのクラスの main メソッドを開始し、次にall
示すように、コンソールに入力して必要なさまざまなクラスを自動的に生成します (ここでは application.yml を無視します)。
ここに最適化されたメモを取ってください
2.書き込みインターフェース
次に、プロジェクト リソースの下に次の内容のファイルを作成しますapplication.yml
(データベース名とパスワードを変更することに注意してください)。
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/we_shopping?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis:
mapper-locations: classpath:/mapper/*Mapper.xml
次に、com.jl15988.shopping
パッケージの下にエンティティ パッケージを作成し、次のように User クラスを作成します。
package com.myblog.entity;
import lombok.Data;
import java.util.Date;
/**
* @author Jaon
* @datetime 2021/10/29 16:13
*/
@Data
public class User {
private Long id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 昵称
*/
private String nick;
/**
* 邮箱
*/
private String email;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
}
次のように、com.myblog パッケージの下にマッパー パッケージを作成し、UserMapper インターフェイスを作成します。
package com.myblog.mapper;
import com.myblog.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @author Jaon
* @datetime 2021/10/29 16:09
*/
@Mapper
public interface UserMapper {
List<User> list();
}
リソースの下にマッパー パッケージを作成し、次のように UserMapper.xml を作成します (ここで記述された SQL ステートメントは、データベースのユーザー テーブル内のすべてのエントリをクエリするものです。すべてのフィールド値をクエリする場合は、* 記号を使用することはお勧めしません)すべてのフィールド値を手動でクエリすることをお勧めします)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.myblog.mapper.UserMapper">
<select id="list" resultType="com.myblog.entity.User">
SELECT id, username, nick, email, create_time createTime, update_time updateTime
FROM t_user
</select>
</mapper>
com.myblog パッケージの下にサービス パッケージを作成し、次のように UserService インターフェイスを作成します。
package com.myblog.service;
import com.myblog.entity.User;
import java.util.List;
/**
* @author Jaon
* @datetime 2021/10/29 16:11
*/
public interface UserService {
List<User> list();
}
次のようにサービスの下に impl パッケージを作成し、UserServiceImpl クラスを作成して UserService インターフェイスを実装します。
package com.myblog.service.impl;
import com.myblog.entity.User;
import com.myblog.mapper.UserMapper;
import com.myblog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Jaon
* @datetime 2021/10/29 16:11
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public List<User> list() {
return userMapper.list();
}
}
次のようにコントローラーの下に UserController を作成します
package com.myblog.controller;
import com.myblog.entity.User;
import com.myblog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author Jaon
* @datetime 2021/10/29 16:22
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@GetMapping("/list")
public List<User> list() {
return userService.list();
}
}
最後に、データベースにデータを作成し、プロジェクトを再起動して、localhost:8080/user/list にアクセスします。
データベースのように
結果にアクセスします (ここでは CSDN プラグインを使用しているため、返されるデータは自動的にフォーマットされます)
a. 時刻のフォーマット
図に示すように、バックエンドから返された時刻形式は実際に必要な形式と一致しないため、次の形式に変換する必要があります。エンティティ クラス属性に @JsonFormat アノテーションを直接追加できます。
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
b. 空のデータを含む属性を非表示にする
図に示すように、返されたデータには null パラメータが含まれています。場合によっては、null パラメータを非表示にすることもできます。これを実現するには、@JsonInclude アノテーションを使用します。
@Data
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class User {
/* 省略代码 */
}
3. クロスドメインの実装
フロントエンドとバックエンドが別々のプロジェクトの場合、現在のインターフェースにアクセスするためにフロントエンドプロジェクトを作成すると、異なるアドレスやポートによってクロスドメインリクエストが発生するため、アクセスできなくなります。図に示すように、バックエンドでクロスドメイン リクエストを開く必要があります。
com.myblog パッケージの下に config パッケージを作成し、次のように WebMvcConfig クラスを作成します。
package com.myblog.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author Jaon
* @datetime 2021/11/1 9:54
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 允许所有的路径可以跨域
registry.addMapping("/**")
// 允许所有来源都可以跨域
.allowedOriginPatterns("*")
// 允许跨域的请求
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
// 允许证书凭证(如果这里设置为true,设置来源为所有只能使用allowedOriginPatterns)
.allowCredentials(true)
// 跨域时间3600秒
.maxAge(3600)
// 允许所以头标题
.allowedHeaders("*");
}
}
}
次に、プロジェクトを再起動して再度確認すると、図に示すように、クロスドメイン エラーが解消され、データが返されることがわかります。
4. グローバル例外処理
バックエンドとしては、エラーが報告された場合でも、フロントエンドにプロンプトを表示するために例外情報を返す必要がありますが、このコードでは、コントローラー層とサービス層の間で転送されるデータを非常に均一なデータ型に制限したり、サービスには戻り値が全くないため、サービス層からフロントエンドに直接返せない例外情報が発生しますが、それをtry-catchで取得するのは面倒なので、グローバル例外処理を一律に定義しています。例外をキャプチャしてフロントエンドに返します。
図に示すように、エラーを確実に報告できる非常に単純なコードを作成しました。
次に、そのアドレスにアクセスすると、500 エラーが報告され、コンソールにエラー メッセージが出力されることがわかります。
次に、次のように com.myblog パッケージの下にハンドラー パッケージを作成し、GlobalExceptionHandler クラスを作成します。
package com.myblog.handler;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author Jaon
* @datetime 2021/11/1 11:27
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
return e.getMessage();
}
}
次に、プロジェクトを再起動してアドレスに再度アクセスすると、戻り情報が変更されていることがわかります。これは、例外をキャッチしてフロントエンドに返したことを意味しますが、コンソールにはエラー メッセージが表示されません。
a. エラーログ
バックエンド プロジェクトにとって、エラー ログは非常に重要であり、後のメンテナンスや問題解決に決定的な役割を果たします。そのため、グローバル例外処理でエラー情報が出力されないのは悪い現象です。次のように @Slf4j を使用してエラー メッセージのログを実装できます。
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
log.error("报错信息:{}", e.getMessage());
return e.getMessage();
}
}
b. カスタム例外
ビジネスロジックでは、グローバル例外ハンドリングクラスでスローされる例外をカスタマイズする必要がある場合がありますが、その際、返されるステータスコードや例外情報の違いを考慮して、グローバル例外ハンドリングと連携するように例外クラスをカスタマイズする必要があります。 。
次のように com.myblog パッケージの下に common.lang パッケージを作成し、MyBlogException クラスを作成します。
package com.myblog.common.exception;
import lombok.Getter;
/**
* @author Jaon
* @datetime 2021/11/1 12:32
*/
@Getter
public class MyBlogException extends RuntimeException {
private Integer code;
private String msg;
public MyBlogException(Integer code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
public MyBlogException(Integer code, String msg, Throwable throwable) {
super(msg, throwable);
this.code = code;
this.msg = msg;
}
public MyBlogException(String msg) {
super(msg);
this.code = 403;
this.msg = msg;
}
public MyBlogException(String msg, Throwable throwable) {
super(msg, throwable);
this.code = 403;
this.msg = msg;
}
}
次に、カスタム例外クラスを使用して、次のような例外をスローできます。
リストインターフェースを変更する
@GetMapping("/list")
public List<User> list() {
List<User> list = userService.list();
if (list.size() <= 0) {
// 如果数据库中没有用户信息则抛出异常
throw new MyBlogException("当前没有用户信息");
}
return list;
}
グローバル例外処理クラスにメソッドを追加
@ExceptionHandler(MyBlogException.class)
public Map<String, Object> handleException(MyBlogException e) {
log.error("报错信息:{}", e.getMessage());
Map<String, Object> map = new HashMap<>();
map.put("code", e.getCode());
map.put("msg", e.getMsg());
return map;
}
その後、ユーザー テーブル内の情報をすべて削除して、再度リクエストすると、フロント エンドが希望した結果を受け取ったことがわかります。
5. 戻りデータの統合カプセル化
フロントエンドとバックエンドが別々のプロジェクトの場合、多くの場合、フロントエンド データの統合処理と調整するために、バックエンドから返されるデータを統合および標準化する必要があります。
commonパッケージの下にlangパッケージを作成し、次のようにResultクラスを作成します。
package com.myblog.common.lang;
import lombok.Data;
/**
* @author Jaon
* @datetime 2021/11/1 13:14
*/
@Data
public class Result {
private Integer code;
private String msg;
private Object data;
public static Result success() {
return success(null);
}
public static Result success(Object data) {
return success(200, data);
}
public static Result success(Integer code, Object data) {
return common(code, "操作成功", data);
}
public static Result fail() {
return fail(null);
}
public static Result fail(Integer code, String msg) {
return common(code, msg, null);
}
public static Result fail(String msg) {
return common(400, msg, null);
}
public static Result fail(Integer code, Object data) {
return common(code, "操作失败", data);
}
public static Result common(Integer code, String msg, Object data) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
result.setData(data);
return result;
}
}
次に、すべての戻り値を次のように置き換えます
// 修改接口返回值
@GetMapping("/list")
public Result list() {
List<User> list = userService.list();
if (list.size() <= 0) {
throw new MyBlogException("当前没有用户信息");
}
return Result.success(list);
}
// 修改异常处理类返回值
@ExceptionHandler(MyBlogException.class)
public Result handleException(MyBlogException e) {
log.error("报错信息:{}", e.getMessage());
return Result.fail(e.getCode(), e.getMsg());
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public Result handleException(Exception e) {
log.error("报错信息:{}", e.getMessage());
return Result.fail(e.getMessage());
}
次にインターフェースにアクセスすると、戻り値の形式が変更されていることがわかります。
この時点で、エントリ インターフェイスの開発は完了です。