一、学习情景:
作为Java程序员,现在领导要求你负责新闻信息系统后端中用户模块,要求你实现该模块的用户注册和登录功能。
要求技术栈:idea、springboot、maven、mybatis、swagger、lombok
二、前置环境:
- 浏览器:chrome(建议)
- Java:Jdk1.8
- 项目管理工具:Maven
- IDE: IntelliJ Idea
- 数据库: Mysql(教师统一在服务器端配置好)
三、创建项目
-
打开idea
-
新建项目
设置项目的基本信息,其中注意jdk版本要与Java版本匹配,这里使用jdk1.8和java8
下一步选择springboot版本和项目依赖
选择新窗口编辑器
-
目录结构(初始)
四、Mysql数据库
数据库下载安装和配置
参见:windows下安装mysql - (jianshu.com)
脚本建库、建表导入
脚本:
-- 零、删库:
-- DROP DATABASE IF EXISTS `db_news`;
-- 一、建库
CREATE DATABASE IF NOT EXISTS `db_news` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';
-- 二、建表、索引等
-- -------------------------------------------------------------------------------------------------------
use db_news;
DROP TABLE IF EXISTS `dt_user`;
-- 用户表:
CREATE TABLE IF NOT EXISTS `dt_user`(
`id` INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',
`username` VARCHAR(32) NOT NULL UNIQUE COMMENT '用户名',
`password` VARCHAR(32) NOT NULL COMMENT '密码',
`mobile` CHAR(11) NOT NULL COMMENT '手机号',
`age` TINYINT UNSIGNED NOT NULL DEFAULT 18 COMMENT '年龄'
) ENGINE=InnoDB COMMENT = '用户表' DEFAULT CHARSET=utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
使用ideaDatabase插件连接Mysql数据库
至此可以看到用户表:dt_user
五、项目架构
六、根据架构调整项目目录
pom.xml配置
pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.7.5
com.sunning
news
0.0.1-SNAPSHOT
news
news
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
mysql
mysql-connector-java
runtime
com.alibaba
druid
1.1.19
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0
org.projectlombok
lombok
true
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
AppNews
org.springframework.boot
spring-boot-maven-plugin
2.7.5
application.yml配置
application.yml
server:
host: localhost
port: 8081
spring:
application:
name: news
# 数据源配置
datasource:
url: jdbc:mysql://${server.host}:3306/mysql?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&rewriteBatchedStatements=TRUE
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: '123456'
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,logback
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# 路径匹配策略
mvc:
pathmatch:
matching-strategy: ant_path_matcher
# 日志配置
logging:
level:
com:
dxy:
odr:
referee:
dao:
mapper: debug
mybatis:
configuration:
# 字段下划线转驼峰
map-underscore-to-camel-case: true
# 打印sql+查询结果
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
开发目录结构
七、用户注册、登录功能实现
dao层之user实体类定义
User.java
package com.sunning.news.dao.pojo;
import lombok.*;
/**
* 用户实体类
*
* @author ckk
* @create 2022-11-02 14:47
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class User {
private Integer id;
private String username;
private String password;
private String mobile;
private Integer age;
}
dao层之mapper数据访问层
UserMapper.java
package com.sunning.news.dao.mapper;
import com.sunning.news.dao.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
/**
* 用户管理mapper
*
* @author ckk
* @create 2022-11-02 14:48
**/
@Repository
public interface UserMapper {
/**
* 新增用户记录,返回自增主键
* username 不重复才新增
* @param user
* @return
*/
@Insert(" insert into db_news.`dt_user`(username, password, mobile, age)" +
" select #{username}, #{password}, #{mobile}, #{age}" +
" where not exists(select username from db_news.`dt_user` where username = #{username})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int register(User user);
/**
* 用户登录,获取用户信息
* @param username
* @param password
* @return
*/
@Select(" select *" +
" from db_news.`dt_user`" +
" where username = #{username} and password = #{password}")
User login(@Param("username") String username, @Param("password") String password);
/**
* 根据username获取用户信息
* @param username
* @return
*/
@Select(" select *" +
" from db_news.`dt_user`" +
" where username = #{username}")
User findByUsername(@Param("username") String username);
/**
* 根据id获取用户信息
* @param id
* @return
*/
@Select(" select *" +
" from db_news.`dt_user`" +
" where id = #{id}")
User findByUid(@Param("id") Integer id);
}
service层之接口定义
UserService.java
package com.sunning.news.service;
import com.sunning.news.dao.pojo.User;
/**
* 用户业务逻辑层接口
*
* @author ckk
* @create 2022-11-02 14:48
**/
public interface UserService {
/**
* 注册业务逻辑
* @param user 要注册的User对象,属性中主键id要为空
* @return
*/
User registerService(User user);
/**
* 登录业务逻辑
* @param uname 账户名
* @param password 密码
* @return
*/
User loginService(String uname, String password);
}
service层之实现类
UserServiceImpl.java
package com.sunning.news.service.impl;
import com.sunning.news.dao.mapper.UserMapper;
import com.sunning.news.dao.pojo.User;
import com.sunning.news.service.UserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 用户业务逻辑层实现类
*
* @author ckk
* @create 2022-11-02 14:49
**/
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public User registerService(User user) {
// 结果
User userDTO = null;
// 当新用户的用户名已存在时
if(userMapper.findByUsername(user.getUsername()) != null){
return null;
}
// 入库
int id = userMapper.register(user);
if(id > 0){
// 查询
userDTO = userMapper.findByUid(id);
}
// 抹掉密码等重要信息
if(userDTO != null){
userDTO.setPassword("");
}
// 返回结果
return userDTO;
}
@Override
public User loginService(String uname, String password) {
// 登录
User user = userMapper.login(uname, password);
// 抹掉密码等重要信息
if(user != null){
user.setPassword("");
}
return user;
}
}
controller控制层
UserController.java
package com.sunning.news.controller;
import com.sunning.news.dao.pojo.User;
import com.sunning.news.service.UserService;
import com.sunning.news.utils.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 用户控制层
*
* @author ckk
* @create 2022-11-02 14:42
**/
@Api(tags = "用户模块")
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@ApiOperation("用户注册")
@PostMapping("/register")
public Result registController(@RequestBody User userAO){
User user = userService.registerService(userAO);
if(user!=null){
return Result.success(user,"用户注册成功!");
}else{
return Result.error("-1","用户名已存在!");
}
}
@ApiOperation("用户登录")
@PostMapping("/login")
public Result loginController(@RequestParam String uname, @RequestParam String password){
User user = userService.loginService(uname, password);
if(user!=null){
return Result.success(user,"用户登录成功!");
}else{
return Result.error("-2","账号或密码错误!");
}
}
}
其他
除了以上包之外,还有config包、utils包,这两者一个是配置类包,另一个是工具类包。
工具类
Result.java
package com.sunning.news.utils;
/**
* 响应结果类
*
* @author ckk
* @create 2022-11-02 14:51
**/
public class Result {
private String code;
private String msg;
private T data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Result() {
}
public Result(T data) {
this.data = data;
}
public static Result success() {
Result result = new Result<>();
result.setCode("0");
result.setMsg("成功");
return result;
}
public static Result success(T data) {
Result result = new Result<>(data);
result.setCode("0");
result.setMsg("成功");
return result;
}
public static Result success(T data,String msg) {
Result result = new Result<>(data);
result.setCode("0");
result.setMsg(msg);
return result;
}
public static Result error(String code, String msg) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
配置类
swagger配置
SwaggerConfig.java
package com.sunning.news.config;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger2配置类
*
* @author ckk
* @create 2022-11-02 16:01
**/
@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
@Bean
public Docket newsApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("newsApi")
// 调用apiInfo方法,创建一个ApiInfo实例,
// 里面是展示在文档页面信息内容
.apiInfo(newsApiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/admin/.*")))
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
// api文档的详细信息
private ApiInfo newsApiInfo(){
return new ApiInfoBuilder()
.title("新闻系统API文档接口测试") //标题
.description("本文档描述接口测试用例") //描述
.version("1.0") //版本
.build();
}
/**
* 解决swagger-ui.html 404无法访问的问题
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 解决静态资源无法访问
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
// 解决swagger无法访问
registry.addResourceHandler("/swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
// 解决swagger的js文件无法访问
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
跨域配置
GlobalCorsConfig.java
package com.sunning.news.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 全局跨域配置
*
* @author ckk
* @create 2022-11-02 15:52
**/
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
.allowedOriginPatterns("*") //开放哪些ip、端口、域名的访问权限,不用allowedOrigins是为了适配swagger2
.allowCredentials(true) //是否允许发送Cookie信息
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") //开放哪些Http方法,允许跨域访问
.allowedHeaders("*") //允许HTTP请求中的携带哪些Header信息
.exposedHeaders("*"); //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
}
};
}
}
启动类配置
NewsApplication.java是启动类,在这里需要配置mybatis的包扫描路径,使用@MapperScan({"com.sunning.news.dao.mapper"})
注解即可,如图:
八、debug运行,swagger测试
在NewsApplication.java启动类上右键点击Debug模式运行项目,如图:
看到此日志,启动成功,如图:
swagger-ui页面进行测试,访问:http://localhost:8081/swagger-ui.html
九、打成jar包运行,swagger测试
maven打包:在idea右侧边的Maven栏目中,找到news-Lifecycle-install功能,双击运行,如图:
在项目的target路径下找到maven打好的jar包:AppNews.jar文件,如图:
在该目录下启动cmd,执行命令:java -jar AppNews.jar
,启动此web服务,如图:
使用swagger进行测试,同第八步骤中所示。