赞
踩
未打开任何项目的,直接点击New Project,已经打开其他项目的,依次点击File -> New -> Project -> Maven
,点击Next,新建Maven项目(这里的Project SDK我们使用的是1.8版本)
然后我们配置Maven项目如下(具体含义可以自行查找)
点击Finnish后(如果已经打开了其他项目,会弹出Open Project的窗口,选择This Window会关闭当前项目,打开创建的项目,选择New Window会在新的窗口打开创建的项目),初始的Maven项目就创建好了
使用SpringBoot很简单,我们只需要在pom.xml中添加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依赖需要点击右上角的小图标,这样才能将依赖引入我们的项目
在src\main\java
下新建包com.jl15988.shopping
(包名往往与组名相同,或组名+模块名,不过不能有大写),然后创建WeShoppingApplication
(这里命名使用的是项目名+Application)类,添加如下代码
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
包,在controller包下创建HelloController
类,并添加如下代码
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端口可能会报错)
使用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;
首先在项目中引入一下依赖
<!-- 数据库 --> <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)
然后在项目resources下创建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
包下创建entity包,然后创建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包下创建mapper包,然后创建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(); }
在resources下创建mapper包,然后创建UserMapper.xml如下(这里写的sql语句是将数据库user表中所有条目查询出来,如果查询全部字段值,不推荐使用*号,推荐手写全部字段值查询)
<?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包下创建service包,然后创建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();
}
在service下创建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(); } }
在controller下创建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的插件,所以自动格式化了返回数据)
如图,后端返回的时间格式与我们实际想要的格式不符合,所以我们需要转换以下格式,可以直接在实体类属性上添加@JsonFormat注解
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
如图,我们所看到的返回数据中有值为null的参数,在某些情况下,我们可能会隐藏值为null的参数,我们可以使用@JsonInclude注解来实现
@Data
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class User {
/* 省略代码 */
}
如果是前后端分离的项目,此时如果我们创建一个前端项目来访问当前接口是访问不通的,因为地址或端口不同造成了跨域请求,此时我们需要后端开放跨域请求,如图
在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("*"); } } }
然后我们重启项目,重新访问可以发现跨域报错消失了,并且能够返回数据,如图
作为后端,就算是报错也需要返回异常信息来提示前端,但是在我们的代码中,controller层与service层之间传递数据不可能局限于一个非常统一的数据类型或者service根本就没有返回值,这就造成了有某些异常信息不能直接从service层返回到前端,如果使用try-catch来捕获就太过于麻烦了,所以我们定义全局异常处理来统一捕获异常并返回给前端
如图,我们写了一个非常简单并且肯定能够报错的代码
然后我们去访问该地址,会发现报了一个500的错,并在控制台打印了错误信息
然后我们在com.myblog包下创建handler包,并创建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(); } }
然后重启项目再次访问地址,发现返回信息变了,这说明我们捕获到了异常,并返回给了前端,但是控制台是没有报错信息的
一个后端项目,报错日志是非常重要的,对于后期维护和问题解决起到了决定性作用,所以全局异常处理没有打印报错信息是一个不太好的现象。我们可以使用@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();
}
}
在我们的业务逻辑中,可能需要自定义异常来抛出,由全局异常处理类来处理,这个时候考虑到返回的状态码和异常信息的不同,我们需要自定义异常类来配合全局异常处理
在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; } }
然后我们就可以使用自定义的异常类来抛出异常了,如
修改list接口
@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;
}
然后删除user表中全部信息,然后再次请求,可以看到前端收到了我们想要的结果
对于前后端分离的项目,后端返回数据往往需要统一规范,来配合前端数据统一处理
在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());
}
然后我们访问一下接口,可以看到返回格式变了
至此,我们的入门接口开发就算是完成了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。