本文章对SpringBoot开发后端项目结构做了简单介绍,并示范了使用SpringBoot+MySQL实现登录的后端功能,与本博客的另一篇文章 Vue 实现登录注册功能(前后端分离完整案例) | MakerHu 的博客 共同组成了前后端分离项目的整体,适合小白上手 Vue + SpringBoot + Mysql 的项目开发。

未经允许请勿转载! 文章首发于快速上手SpringBoot项目(登录注册保姆级教程) | MakerHu的博客

强烈建议大家移步至我的个人博客中查看,因为一些步骤可能有更新,但没同步到此处。

前后端完整项目演示:

本文章只涉及后端教程,前端教程请看本人的另一篇文章:

前端教程: Vue 实现登录注册功能(前后端分离完整案例) | MakerHu 的博客

前置条件

使用本教程的前置条件是开发环境中已安装了以下几个东西,若无可以先找相关教程安装配置好。

管理工具: maven

IDE: IDEA

数据库: MySQL

测试工具: Postman(非必须,但方便测试且安装和使用都挺简单的)

创建项目

注意:创建项目时保持网络通畅

  1. 打开IDEA

  2. 新建项目

    情况一:

    情况二:

    设置项目的基本信息,其中注意jdk版本要与Java版本匹配,这里使用jdk1.8和java8

选择SpringBoot版本,选择项目依赖(依赖可以创建完项目后在pom文件中修改)

至此项目就创建完成啦!

目录结构(初始状态)

配置数据库

创建完项目后,如果直接运行项目,我们会发现项目报错了

报错的原因是我们在创建项目时导入了数据库相关的依赖,但是项目却还没有进行数据库相关配置

所以接下来我们先进行数据库的配置

创建数据库

要配置数据库,首先咱们得有个数据库,因此我们先用MySQL创建一个。由于本项目要演示登录注册功能的实现,所以在此我将创建一个用户表,保存用户的账号信息。

  1. 按Win+R打开“运行”,输入cmd

  1. 输入mysql -u root -p后输入密码,登录MySQL

  2. 创建数据库create database logindemologindemo为数据库名,根据你的情况修改

  3. 进入数据库use logindemo

  4. 创建user表

    CREATE TABLE user
    (uid int(10) primary key NOT NULL AUTO_INCREMENT,uname varchar(30) NOT NULL,password varchar(255) NOT NULL,UNIQUE (uname)
    );
    

    uid: 用户编号,主键,自增

    uname: 用户名,作为登录的账号(业务主键),不可重复

    password: 密码,因为可能要加密,所以长度设了较长的255

  5. 查看表是否创建成功

    desc user;

    到这数据库就创建完成啦,接下来就是在项目中配置数据库相关信息了。

配置数据库

  1. 找到配置文件application.properties

  2. 输入数据库相关配置信息(此处配置了项目端口号为8081,可不配置,默认端口号为8080)

    注意:配置url处logindemo改为你的数据库名称

    # 配置端口号为8081
    server.port=8081# 配置数据库
    # 配置驱动
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    # 若连接的是云数据库则将localhost改为云端ip
    spring.datasource.url=jdbc:mysql://localhost:3306/logindemo?serverTimezone=UTC
    # Mysql用户
    spring.datasource.username=root
    # Mysql对应用户密码
    spring.datasource.password=123456
    

    现在再次运行项目就能成功运行啦!

  3. 在IDEA中连接数据库(此步非必须,只是为了开发方便)

    在IDEA中连接数据库可以让我们在开发时直接可视化查看数据库的详细信息,建议配置一下。

    配置数据库基本信息

    注意:这一步有可能出现时区错误或者缺少依赖文件!!!

    解决方案

    **时区错误:**见图中配置时区

    **缺少文件:**根据提示点击下载,但由于服务器在外网,有可能需要科学上网

    完成以上配置后就能在IDEA中管理数据库啦!

项目架构图

在说项目的目录结构之前,我们先来聊一聊后端的架构大概是什么样的,方便我们对目录结构的理解。

  • 数据持久层是的目的是在java对象与数据库之间建立映射,也就是说它的作用是将某一个Java类对应到数据库中的一张表。在我们的项目中,就将创建一个实体类User映射到数据库的user表,表中的每个字段对应于实体类的每个属性。而之前配置的JPA的作用就是帮助我们完成类到数据表的映射。

    • repository: 存放一些数据访问类(也就是一些能操纵数据库的类)的包,比如存放能对user表进行增删改查的类
    • domain:存放实体类的包,比如User类,其作为对应数据库user表的一个实体类
  • 业务逻辑层的作用是处理业务逻辑。比如在本项目中,我们就在业务逻辑层实现登录注册的逻辑,像是判断是否有用户名重复,密码是否正确等逻辑
    • service: 存放业务逻辑接口的包
    • serviceImpl: 存放业务逻辑实现类的包,其中的类实现service中的接口
  • 控制层的作用是接收视图层的请求并调用业务逻辑层的方法。比如视图层请求登录并发来了用户的账号和密码,那么控制层就调用业务逻辑层的登录方法,并将账号密码作为参数传入,在将结果返回给视图层。
    • controller: 存放控制器的包。比如UserController
  • 视图层的作用是展现数据,由于本项目写的是纯后端,就不展开解释视图层了。

注意:根据架构我们可以发现,最佳的开发方式是自底向上开发,因为包之间的调用是上层调用下层,所以下层先实现能保证实现多少测试多少

完善项目的基本目录结构

根据上述架构图的设计,我们就能创建对应的包让我们的项目框架更加清晰了。

  1. 创建各种包(以domain包为例)

    注意本项目中service与serviceImpl包为父子关系,也可以并列,这取决于你的喜好

    最终效果见下一步

  2. 最终目录结构

    包含domain repository service serviceImpl controller utils config

    这时候眼尖的同学就发现了,怎么还多了俩: utils config

    这两个包的作用:

    • utils: 存放工具类,一些自己封装的工具
    • config: 存放配置类,一些配置如登录拦截器,安全配置等

    这里先建好了再说,具体怎么用之后会说。

登录注册功能实现

根据框架特点,我们将自底向上开发,所以将按照 实体类-dao-service-serviceImpl-controller 的顺序逐步开发。

所有类或接口的目录位置

为了方便你在下面的教程中明确的知道文件应该创建在什么位置,在此我就先把所有文件的目录位置展示出来了,你可以在需要的时候随时回来查看,现在可以先跳过这一步。

实现User实体类

  1. 在domain中创建User.java

  2. 创建对应user表中字段的属性

    其中注意要添加@Table(name = "user")@Entity注解

    • @Table(name = “user”) 说明此实体类对应于数据库的user表
    • @Entity 说明此类是个实体类

    主键uid上要加上@Id@GeneratedValue(strategy = GenerationType.IDENTITY)注解

    //domain中的User.java
    package com.springboot.springbootlogindemo.domain;import javax.persistence.*;@Table(name = "user")
    @Entity
    public class User {// 注意属性名要与数据表中的字段名一致// 主键自增int(10)对应long@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private long uid;// 用户名属性varchar对应Stringprivate String uname;// 密码属性varchar对应Stringprivate String password;}
    

  3. 为属性生成get,set方法

    • 将光标移至要插入get, set方法的位置

    • 右键-generate-getter and setter

    • 选中所有属性-OK

    • 最后得到User.java(也可以纯手敲)

      package com.springboot.springbootlogindemo.domain;import javax.persistence.*;@Table(name = "user")
      @Entity
      public class User {// 注意属性名要与数据表中的字段名一致// 主键自增int(10)对应long@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private long uid;// 用户名属性varchar对应Stringprivate String uname;// 密码属性varchar对应Stringprivate String password;public long getUid() {return uid;}public void setUid(long uid) {this.uid = uid;}public String getUname() {return uname;}public void setUname(String uname) {this.uname = uname;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
      }
      

      至此User实体类就创建好啦,如果要实现其他表的实体类也类似。

实现UserDao

  1. 在repository包中创建UserDao接口

  2. 添加一些访问数据库的方法(这里添加的是根据用户名查询用户方法)

    • 首先要添加注解@Repository
    • 接口要继承JpaRepository,这样JPA就能帮助我们完成对数据库的映射,也就是说接口里写的方法只要符合格式可以不需要实现SQL语句就能直接用了。
    • 如果JPA没有提供你想要的方法,可以自定义SQL语句

    package com.springboot.springbootlogindemo.repository;import com.springboot.springbootlogindemo.domain.User;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;@Repository
    public interface UserDao extends JpaRepository<User, Long> {User findByUname(String uname); //通过用户名uname查找用户,注意要按照JPA的格式使用驼峰命名法User findByUnameAndPassword(String uname, String password);//通过用户名uname和密码查找用户
    }
    

    由于我们只实现登录注册功能,所以只要有根据账号密码查询用户和插入用户信息的方法就行了,这里我们已经实现了根据用户名密码查找用户的方法,而插入用户信息的方法save(object o)JPA已经帮我们实现了,可以直接调用,这里就不需要写了。

    注意: 这里接口方法的命名要按照JPA提供的命名格式,比如findBy, deleteBy等等,且要求驼峰命名法。如果自定义查询方法可以不遵守这个规则

    自定义查询方法例子(本项目不需要用到):

    @Query(value = "select * from user where uname LIKE ?1 OR email LIKE ?2 OR lastdid LIKE ?3 OR uid LIKE ?4",nativeQuery = true)
    Page<User> findUserswithoutgender(String uname,String email,String lastdid,String uid,Pageable request
    );
    

实现UserService

  1. 在service包中创建UserService接口

  2. 添加登录注册需要用到的业务逻辑方法

    • 最终UserService的完整代码
    package com.springboot.springbootlogindemo.service;import com.springboot.springbootlogindemo.domain.User;public interface UserService {/*** 登录业务逻辑* @param uname 账户名* @param password 密码* @return*/User loginService(String uname, String password);/*** 注册业务逻辑* @param user 要注册的User对象,属性中主键uid要为空,若uid不为空可能会覆盖已存在的user* @return*/User registService(User user);
    }
    
  3. 完成了接口方法的定义,接下来是在UserServiceImpl中实现这些方法啦

实现UserServiceImpl

我们将在UserServiceImpl中实现UserService中的方法,完整的UserServiceImpl代码在此步骤的最后一小步里

  1. 在serviceImpl包中创建UserServiceImpl类

  2. 添加需要实现的方法

    • 添加implements UserService

      此时会报错,但没关系,只是因为方法还没实现。

    • 鼠标悬停在红色波浪线自动生成需要实现的方法(也可以手动一个个写)

    • 生成方法后的样子

  3. 实现登录业务逻辑

    • 因为要用到UserDao中的方法,所以先通过@Resource注解帮助我们实例化UserDao对象

    • 登录业务逻辑代码

      @Resource
      private UserDao userDao;@Override
      public User loginService(String uname, String password) {// 如果账号密码都对则返回登录的用户对象,若有一个错误则返回nullUser user = userDao.findByUnameAndPassword(uname, password);// 重要信息置空if(user != null){user.setPassword("");}return user;
      }
      
  4. 实现注册业务逻辑

    • 注册业务逻辑代码

      @Override
      public User registService(User user) {//当新用户的用户名已存在时if(userDao.findByUname(user.getUname())!=null){// 无法注册return null;}else{//返回创建好的用户对象(带uid)User newUser = userDao.save(user);if(newUser != null){newUser.setPassword("");}return newUser;}
      }
      
  5. 添加@Service注解

  6. 最终UserServiceImpl完整代码

    package com.springboot.springbootlogindemo.service.serviceImpl;import com.springboot.springbootlogindemo.domain.User;
    import com.springboot.springbootlogindemo.repository.UserDao;
    import com.springboot.springbootlogindemo.service.UserService;
    import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service
    public class UserServiceImpl implements UserService {@Resourceprivate UserDao userDao;@Overridepublic User loginService(String uname, String password) {// 如果账号密码都对则返回登录的用户对象,若有一个错误则返回nullUser user = userDao.findByUnameAndPassword(uname, password);// 重要信息置空if(user != null){user.setPassword("");}return user;}@Overridepublic User registService(User user) {//当新用户的用户名已存在时if(userDao.findByUname(user.getUname())!=null){// 无法注册return null;}else{//返回创建好的用户对象(带uid)User newUser = userDao.save(user);if(newUser != null){newUser.setPassword("");}return newUser;}}
    }
  7. 至此UserServiceImpl就写完啦!

实现工具类Result

工具类Result的作用是作为返回给前端的统一后的对象。也就是说返回给前端的都是Result对象,只是对象中的属性不太一样,这样方便前端固定接收格式。

  1. 在utils包中创建Result类

  2. 最终Result代码

    package com.springboot.springbootlogindemo.utils;public class Result<T> {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 <T> Result<T> success(T data) {Result<T> result = new Result<>(data);result.setCode("0");result.setMsg("成功");return result;}public static <T> Result<T> success(T data,String msg) {Result<T> 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;}
    }
    

    可以看出Result是个模板类,因此想要返回什么数据类型给前端都行,如Result<User>,要是没看懂没关系,看到下面就知道怎么用了。因为里面有很多静态方法,可以直接用类名.方法名调用。

实现UserController

  1. 在controller包中创建UserController类

  2. 添加@RestController@RequestMapping("/user")注解,注入UserService

    • 注解@RequestMapping中的"/user"是这个控制器类的基路由

  3. 实现登录的控制

    这里的@PostMapping("/login")表示处理post请求,路由为/user/login

    @PostMapping("/login")
    public Result<User> loginController(@RequestParam String uname, @RequestParam String password){User user = userService.loginService(uname, password);if(user!=null){return Result.success(user,"登录成功!");}else{return Result.error("123","账号或密码错误!");}
    }
    
  4. 实现注册的控制

    这里的@PostMapping("/register")表示处理post请求,路由为/user/register

    @PostMapping("/register")
    public Result<User> registController(@RequestBody User newUser){User user = userService.registService(newUser);if(user!=null){return Result.success(user,"注册成功!");}else{return Result.error("456","用户名已存在!");}
    }
    
  5. 完整的UserController代码

    package com.springboot.springbootlogindemo.controller;import com.springboot.springbootlogindemo.domain.User;
    import com.springboot.springbootlogindemo.service.UserService;
    import com.springboot.springbootlogindemo.utils.Result;
    import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;@RestController
    @RequestMapping("/user")
    public class UserController {@Resourceprivate UserService userService;@PostMapping("/login")public Result<User> loginController(@RequestParam String uname, @RequestParam String password){User user = userService.loginService(uname, password);if(user!=null){return Result.success(user,"登录成功!");}else{return Result.error("123","账号或密码错误!");}}@PostMapping("/register")public Result<User> registController(@RequestBody User newUser){User user = userService.registService(newUser);if(user!=null){return Result.success(user,"注册成功!");}else{return Result.error("456","用户名已存在!");}}
    }
    

处理跨域访问问题

跨域问题可以简单理解成如果你的前端项目的IP地址端口号和后端的IP地址端口号不一样,就会导致前端无法获取到数据,这是一个规定。而在前后端分离开发的项目中,前后端项目的端口号一般都是不一样的,假设我们这个项目的前端端口号是 8080,后端端口号是 8081,就会造成跨域访问的问题,跨域访问的问题可以在前端解决也可以在后端解决,后端只要加上一个配置文件就行了

  • config文件下创建全局跨域配置类GlobalCorsConfig.java

  • GlobalCorsConfig.java 文件
    注意!!!SpringBoot2.4.0 以后下方 allowedOrigins 需要被 allowedOriginPatterns 代替!!!!

    package com.springboot.springbootlogindemo.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;@Configuration
    public class GlobalCorsConfig {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**")    //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置.allowedOrigins("*")    //开放哪些ip、端口、域名的访问权限 SpringBoot2.4.0以后allowedOrigins被allowedOriginPatterns代替.allowCredentials(true)  //是否允许发送Cookie信息.allowedMethods("GET", "POST", "PUT", "DELETE")     //开放哪些Http方法,允许跨域访问.allowedHeaders("*")     //允许HTTP请求中的携带哪些Header信息.exposedHeaders("*");   //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)}};}
    }
    

    处理跨域问题是为前后端分离开发做铺垫,这里这样配置好就行了,暂时放着不需要管,等开发前端 Vue 项目时就不会出问题了。

    至此所有的代码就都写完啦!!!

    接下来就是运行测试一下是否成功就行了。

Postman测试

  1. 打开postman

  2. 测试注册用户

    输入选则请求方式Post,输入路由http://localhost:8081/user/register,输入用户json对象后点击Send

    {"uname": "hhh","password": "123"
    }
    

    成功收到后端返回消息

  3. 登录测试

    类似于注册测试

    • 请求方式:POST
    • url:http://localhost:8081/user/login
    • 参数:见图中4,5步

    至此整个项目都写完并测试完啦!感谢你能耐心看到这,希望本教程对你有所帮助。

项目源代码

  • Vue 前端:MakerHu/vue-login-demo (github.com)
  • SpringBoot 后端:MakerHu/springboot-login-demo (github.com)

相关推荐

  • 前端教程:Vue 实现登录注册功能(前后端分离完整案例) | MakerHu 的博客

快速上手Springboot项目(登录注册保姆级教程)相关推荐

  1. springboot项目登录+注册

    springboot 整合 mybatis + thymeleaf 登录注册 学习网址 springboot+jsp https://blog.csdn.net/qq_40205116/article ...

  2. 手撸一个动态数据源的Starter 完整编写一个Starter及融合项目的过程 保姆级教程

    手撸一个动态数据源的Starter! 文章目录 手撸一个动态数据源的Starter! 前言 一.准备工作 1,演示 2,项目目录结构 3,POM文件 二.思路 三.编写代码 1,定义核心注解 Ds 2 ...

  3. Springboot 打包神器Maven 保姆级教程

    一.介绍 Maven 是基于项目对象模型 (POM project object model),可以通过一小段描述信息(配置)来管理项目的构建,报告和文档的软件项目管理工具,简单的说就是用来管理项目所 ...

  4. 【经典游戏】坦克大战 Unity2D项目实战(保姆级教程)

    主要内容: 1.Unity3D引擎中的基础设置. 2.2D场景的搭建,预制体制作. 3.2D动画的制作. 4.图片图集的有关知识. 5.碰撞器,触发器,碰撞检测与触发检测. 6.2D游戏渲染的一些知识 ...

  5. 原来Vinted注册这么简单!Vinted注册保姆级教程分享

    如果是日本的二手平台代表是煤炉,美国是PoshMark,那欧洲呼声最高的就是Vinted了,今天东哥就给大家科普一下Vinted这个平台,教大家怎么去成功注册Vinted,开启自己的Vinted跨境电 ...

  6. go项目部署服务器保姆级教程(带图)

    第一步把项目打包 1.确保本地goland的操作系统为linux go env 找到GOOS如果为window就修改为Linux 修改命令为 go env -w GOOS=linux 2.打包 在项目 ...

  7. 树莓派3b+快速编译opencv成功案例指导(保姆级教程)

    如果对opencv的版本没有特别要求建议直接去找已经安装好opencv的镜像.那个才是最快的速度! 真是亲身体验!就差人傻了!先1我的对树莓派基本小白一个好吧,只能出一个傻瓜式教程了. 不想看傻瓜式教 ...

  8. vue项目打包wap2app项目生成apk保姆级教程适合新手看,建议收藏

    一.需要提前准备的有: 1.已部署到云端的网站+域名 2.下载软件HBuilder X, 下载地址官网. 3.创建项目 重要的配置部分来了 二.部分配置修改 问题1:如果你的网站没有事先为顶部预留安全 ...

  9. 保姆级教程——将springboot项目部署到阿里云服务器(小白包会)

    保姆级教程--将springboot项目部署到阿里云服务器(小白包会) 前言: 昨天本想着看论文,结果发现找的论文和课题不一致.那干点什么好呢?那就把我的毕业设计(一个springboot项目)部署到 ...

最新文章

  1. CentOS部署JAVA程序、安装Tomcat以及安装导入mysql文件的方法
  2. Kaggle发布数据科学最新报告!82%男性, 62%硕博,薪酬6位数居多
  3. pandas使用to_datetime函数把dataframe的字符串日期数据列转化为日期格式日期数据列( strings to datetime in dataframe column)
  4. k最邻近算法——加权kNN
  5. [Grid Layout] Specify a grid gutter size with grid-gap
  6. Delphi XE2 之 FireMonkey 入门(13) - 动画(下)
  7. 吴恩达深度学习——2.3 logistic回归损失函数
  8. matlab矩阵信号,matlab - 如何在Matlab中使用移位版本的信号样本创建矩阵? - SO中文参考 - www.soinside.com...
  9. 配置tomcat 7控制台账号
  10. 基于CUDA的离散傅里叶变换(Discrete Fourier Transform,DFT)
  11. EntityFramework中IEnumerable和IQueryable的含义和区别
  12. QT_TableWidget插入checkbox
  13. Ubuntu NumPy 安装
  14. python pyqt5 股票分时_Python使用PyQtGraph绘制股票行情K线图
  15. Python的三目表达式and简短语法
  16. 发光二极管工作电流分析
  17. 基于人工势场法的车辆编队轨迹规划matlab仿真验证
  18. 华为系统wifi服务器失败是怎么回事儿,wifi 用云服务器异常
  19. [从零开始unity3D]“五子连珠”游戏实现,网格数组的创建(1)
  20. sql server 安全配置及建议配置

热门文章

  1. 强化学习之贝尔曼方程
  2. 【Python】8.有益的探索
  3. 计算机网络与综合布线系统设计,谈计算机网络综合布线系统设计
  4. 使用sklearn训练模型出现【DataConversionWarning: A column-vector y was passed when a 1d array was expected】
  5. centos7 修改时间、时区问题
  6. vue获取上一个路由地址
  7. 依赖倒置、控制反转、依赖注入
  8. 利用Python实现scissors-rock-paper-lizard-Spock小游戏
  9. 【plang 1.4.6】Plang高级编程语言(发布)
  10. cas 6.2 Incompatible because this component declares an API of a component compatible with Java 11