声名
提示:本博客主要通过实现用户注册功能,帮助小白熟悉和理解以及使用在Spring Mvc框架下开发项目的基本流程
项目工具版本:2019.3 Idea64、MySQL5.5.6版本
提示:以下是本篇文章正文内容,下面案例可供参考
一、创建与配置
1. 项目创建
- 创建新Project
- 选择配置依赖,包括Web、SQL部分
2. 依赖配置
2.1 配置pom.xml
在第33行换行增加一句:
<version>5.1.49</version>
2.2 配置application.properties
- 配置数据库
在application.properties中配置(我的数据库密码为null,所以不写即可)
# 配置数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=
spring.datasource.url=jdbc:mysql://localhost:3306/upc_demo?characterEncoding=utf8
- 配置映射文件
在resources目录下创建mappers文件夹
在application.properties中配置
mybatis.mapper-locations=classpath:mappers/*.xml
- 设置日志级别
在application.properties中设置日记级别为debug级别,即控制台可以显示SQL语句,可让开发人员可以检测是否出错(等到项目全部完成后需要注释掉)
logging.level.com.upc.oa.mapper=debug
- 配置服务器:
在application.properties中配置Web访问地址的端口和项目根目录
配置:端口8088,项目根目录为 /oa
server.port=8088
server.servlet.context-path=/oa
服务地址:http://localhost:8088/oa
注意:
- 服务器默认配置:端口8080,无根目录,由于tomcat服务器使用了8080,为了不冲突,我们一般重新配置
- MySQL服务器使用了3306端口,所以一般我们配置自己服务器端口时也不选择3306
- 最终配置如下:
# 配置数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=
spring.datasource.url=jdbc:mysql://localhost:3306/upc_demo?characterEncoding=utf8
# 配置映射文件
mybatis.mapper-locations=classpath:mappers/*.xml
# 设置日志级别,显示SQL语句(项目完成后注释掉)
logging.level.com.upc.oa.mapper=debug
# 配置服务器
# 端口3306数据库使用了,端口8080tomcat使用了,所以我们要单独配置
server.port=8088
server.servlet.context-path=/oa
二、项目后端
注意:
- 项目后端流程的详细步骤:基于MyBatis操作MySQL数据库的基本步骤
- 查询结果分页显示:基于MyBatis的查询结果分页显示
- 动态SQL查询:基于MaBatis编写动态SQL语句
- 关联映射查询:基于MyBatis的关联映射查询
1. 创建数据库表格
在navicat的对应数据库中,根据需求创建自己表格即可,我们创建存放用户注册信息的user_Info表格
注意:
- 注意创建表格时userId是系统自增的主键,不需要用户注册时输入,所以后端的SQL语句中不需要插入userId数据
- 注意userStatus表示用户账号的状态,默认为1即正常状态,若账号被删除或者拉黑可能是别的状态,这是后台管理员的任务,也不需要用户注册时输入,所以后端的SQL语句中也不需要插入userStatus数据,一般用户注册成功后都是默认为1
2. 搭建项目目录
在XXXApplication同级目录中创建:controller、mapper、service、po、dto的package
3. 创建实体类
3.1 自动生成po实体类
- 打开工具
- 连接数据库
- 修改配置
- 选择要生成实体类的数据库表格,我们选择user_Info
- 选择实体类存放文件,自动生产的实体类要统一放在po包里,ok后生成的UserInfo实体类存放在po包中
3.2 创建dto实体类
dto实体类主要用于作传递参数的数据类型
- 在dto包下,创建dto实体类 Java class文件,命名为UserInfoDto(因为我们要继承UserInfo实体类)
- 让UserInfoDto实体类继承UserInfo实体类即可
package com.upc.oa.dto;
import com.upc.oa.po.UserInfo;
public class UserinfoDto extends UserInfo {
}
4. 操作数据库
4.1 创建接口文件
(1) 创建函数接口
在mapper包中,创建UserInfo的函数接口,命名为UserInfoMapper
(2) 编写函数接口
主要编写一个接收参数的函数接口,注意声名@Mapper
package com.upc.oa.mapper;
import com.upc.oa.dto.UserinfoDto;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserinfoMapper {
int save(UserinfoDto dto);
}
4.2 创建映射文件
(1) 创建文件
- 点击函数接口中的类名UserInfoMapper,选择黄色灯泡,选择蓝条部分,自动生成映射文件
- 选择映射文件存放位置
- 选择接口文件中我们编写的函数接口名sava,选择红色叹号,点击Generate statement
- 选择生成语句类型,自动在映射文件中产生该函数接口的语句,我们是注册,就是向数据库插入数据,所以选择Insert Statement
- 此时映射文件中已有如下代码:
(2) 编写SQL语句
- 现在可以检测SQL语法的文件中编写,我们编写向user_info表格插入数据的插入语句
- 粘贴在映射文件中并完成后续部分
<?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.upc.oa.mapper.UserinfoMapper">
<insert id="save">
insert into user_info
(userName, userPwd, userRealName, userSex, userEmail)
VALUES (#{userName},#{userPwd},#{userRealName},#{userSex},#{userEmail})
</insert>
</mapper>
4.3 测试后端
模拟后端接收到前端提交的数据后,检测后端执行过程是否正确。
注意:
我们检测的是过程的正确性,尤其是对于后端内容涉及表格的增删改情况时,实际上我们不需要,也最好不要在测试阶段对数据库表格进行改动,所以我们在测试结束后要进行事物回滚,即测试结束后撤销对数据库的操作。这里涉及一个注解@Transactional,当测试结束后,这个注解会帮助我们进行事物回滚。
(1) 创建测试文件
- 创建文件
- 选择要测试的函数接口
(1) 编写测试文件
- 添加注解
- 编写测试:主要是模拟前端传递来的数据,然后传递给函数接口
package com.upc.oa.mapper;
import com.upc.oa.dto.UserinfoDto;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class UserinfoMapperTest {
@Resource
private UserinfoMapper userinfoMapper;
@Test
@Transactional //执行成功后回滚数据
void save() {
// 设计、模拟前端传入的参数:创建结构体dto,给其中参数赋值
UserinfoDto dto = new UserinfoDto();
dto.setUserName("ross");
dto.setUserPwd("666666");
dto.setUserRealName("张三");
dto.setUserEmail("daimi5566@126.com");
// 调用函数接口userinfoMapper.save( )函数,操作成功返回 1,row为1
int row = userinfoMapper.save(dto);
// 这是一个函数:若row返回1,则提示操作成功
assertEquals(1,row);
}
}
(3) 测试
测试结果如下,即成功,即看到rollback[true]即告诉我们后端运行成功,并成功事务回滚了
三、项目前端
注意: 整个前端的编写流程应该为 Html部分-Css部分-业务逻辑-控制器-Js,但是在老师讲授时为了我们更好理解是按前端数据的流向编写的:Html部分-Css部分-Js-控制器-业务逻辑。所以这里的代码都有部分流程上的逻辑问题,例如Js中提交数据的路径参数提前就写好了,实际应该写好控制器,才能写对应的路径。
1. 创建界面文件
在static文件夹里创建login.html文件
1.1 Html部分
主要任务: 编写网页的基本内容
注意:
- Html里的标签,也称为控件,控件大到div、table,小到 tr、td、input
- 这里只提供我对html标签及其中属性的理解,至于详细用法可参考代码中的注解
标签(控件) | 个人理解 |
---|---|
div | 区隔标记,将div标签中的控件,都放置在该div标签的区域内。我们除了可以修饰 html 界面本身的背景色,还可以单独修饰div标签区域的背景色。 |
from | 主要作用之一是向后端提交数据,但是本项目不再使用 from 表单提交数据,所以 from 表单添加与否无所谓,即使添加了也不用设置参数。 |
table | 约束 table 标签里的行和列,让它们更规整。表格顾名思义,表格里的行和列就是整整齐齐的,所以在table里创建的行和列都是自动规范的。 |
tr | 行标签,创建一行,该行可以放置很多列。 |
td | 列标签,创建一列,一般是嵌套在行标签里,等于是设置该行标签里的一列。 |
input | 输入标签,在界面中提供一个可输入文本框,input标签接收用户在对应文本框中的输入数据,除了可以提供输入文本框,还可提供单选按钮服务,非常银杏化。 |
button | 按钮标签,就是网页中的按钮,而若button的type是button,则button标签等同一个事件触发按钮,点击了它会触发一个事件,这个事件做什么我们自己编写;而它自带的有在 from 表单提交数据 post、重置文本框数据 reset 等等 |
标签中的属性 | 个人理解 |
---|---|
id=“” | 可以理解为控件的变量名,我们一般将需要进行修饰、操作的控件配置 id,目的是为了精确指定操作的控件。 |
type=“” | 类型,在input标签中,可以是文本类型、密码类型、单选项类型;在button选项中,可以是按钮类型,也可以是提交数据类型、重置文本框类型。 |
name=“” | 主要用于input,是为了 from 表单提交数据时,确定每个界面输入数据对应到后端的哪些参数,name要与对应后端的参数名一致 |
placeholder=“” | 主要用于input中,是在用户输入前的提示,文本框中的浅色文字 |
class=“” | 主要用于Css修饰Html界面时,类选择器选择有对应class的控件进行修饰 |
代码部分: 注意在body部分编写界面
<!--框出区域-->
<div id="container">
<!--增加表单与否无所谓了,因为我们向后台提交数据不再用表单提交了,所以即使添加了表单也不用设置参数了-->
<form>
<!-- table可以约束我们定义的行和列,让它们更规整 -->
<table>
<!--设置 登录名 行-->
<tr>
<td>登录名:</td>
<td>
<!-- id 控件的变量名,name是对应到后端的参数 (不过用不上了,写不写无所谓) -->
<input type="text" id="userName" name="userName" placeholder="登录名称" class="input">
</td>
<!-- 多加一列,提示用户名填写什么 -->
<td>
<div id="userNameMsg">
登录名包含数字、字母任意组合
</div>
</td>
</tr>
<!--设置 密码行 行-->
<tr>
<td>登录密码:</td>
<td>
<input type="password" id="userPwd" name="userPwd" placeholder="登录密码" class="input">
</td>
<td>
<div id="userPwdMsg">
登录密码6-12之间
</div>
</td>
</tr>
<!--设置 确认密码行 行-->
<tr>
<td>确认密码:</td>
<td>
<!-- 这里是确认密码,不过不再向参数传递数据 -->
<input type="password" id="rePwd" placeholder="确认密码" class="input">
</td>
<td>
<div id="rePwdMsg">
确认密码必须与密码一致
</div>
</td>
</tr>
<!--设置 真实姓名 行-->
<tr>
<td>姓名:</td>
<td>
<input type="text" id="userRealName" name="userRealName" class="input">
</td>
<td>
<div id="userRealNameMsg">请输入姓名</div>
</td>
</tr>
<!--设置 性别 行-->
<tr>
<td>姓名:</td>
<td>
<!-- radio是单选按钮 ,名字分别叫男、女,选择男则前端返回的数值为 1,反之选择女返回2-->
<!-- 单选项里name是比加的属性,且要填对对应的后端参数 -->
<input type="radio" id="boy" name="userSex" value="1"checked> 男
<input type="radio" id="girl" name="userSex" value="2"checked> 女
</td>
</tr>
<!--设置 邮箱 行-->
<tr>
<td>邮箱:</td>
<td>
<input type="email" id="userEmail" name="userEmail" class="input">
</td>
<td>
<div id="userEmailMsg">
</div>
</td>
</tr>
<!--设置 按钮 行-->
<tr>
<td></td>
<td>
<button type="button" id="btnReg">注册</button>
</td>
<td>
<!--设置 重置按钮 -->
<button type="reset">重置</button>
</td>
</tr>
</table>
</form>
</div>
1.2 Css部分
主要任务: 修饰html编写的主体功能。
编写位置: 编码位置在head标签,添加style标签后即可编码。
存在问题: 界面主要控件都布置好了,这个修饰界面部分和界面控件部分是分离的,如何去修饰我们想要的控件呢?Css语法提供了三种方法去选择我们要修饰的控件,称为选择器(是不是很银杏化)
选择器 | 作用(个人理解) |
---|---|
类选择器 | 插眼法:我们要修饰的对象是谁,我们在对应控件里插个class=“className”属性,我们可以自己命名className |
id选择器 | 实名制法,每个控件基本都有自己的 id,我们要修饰哪个控件,直接选择这个控件的 id 进行修饰 |
标签选择器 | 分类法:假如使用了 input标签的选择器,则它会自动将所有input控件都修饰 |
代码:
主要用法在代码注释中:
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- sytle标签里写Css,修饰网页 -->
<style type="text/css">
/*
*{} :标签选择器,*{}默认选择了所有标签
margin: 0; :各个非嵌套关系的容器之间的边框间隔变为 0
padding: 0; :嵌套关系的容器之间的间隔也为 0,(未懂)
*/
*{
margin: 0;
padding: 0;
}
/*
body{}:标签选择器,选择页面主体body控件进行修饰
background-color: red; :设置主体背景色是红色
*/
body{
background-color: red;
}
/*
body,html{}:标签选择器,选择了body、html控件进行修饰
width: 100%; height: 100%; :宽高都为100%,是为了辅助div撑满网页而作的操作
*/
html,body{
width: 100%;
height: 100%;
}
/*
#container{} :id选择器,选择的是id="container"的控件进行修饰,就是下面的div控件
background-color: #cae8ff; :让该控件的背景色为#cae8ff
height: 100%; :该div控件的高设置为主体的100%程度,即撑满主体(但前提是body,html{}的宽高都要100%,前面已经进行设置)
*/
#container{
background-color: #cae8ff;
height: 100%;
}
/*
.input{}:类选择器,默认修饰所有带有class="input"属性的控件,我们给几个input控件配置了该class
我们不但设置了宽、高、到其他边框的间隔大小,还有:
border-radius: 5px; :边框线的粗为5px
border: 1px solid; :边框的线为间隔为1px的虚线
*/
.input{
width: 200px;
height: 30px;
margin: 10px;
border-radius: 5px;
border: 1px solid;
}
/*
.input:hover{} :类选择器,对所有有class="input"属性的控件进行修饰
border-color: red; :当鼠标光标悬浮在被修饰的空间上时,边框变成红色-->
*/
.input:hover{
border-color: red;
}
/*
button{} :标签选择器,自动修饰所有button的标签控件
我们设置了按钮大小 以及形状,除此之外还有:
border-radius: 50%:以高度的50%、宽度的50%进行画圈,当宽高相同时会进行画圆 ;不一致时多为椭圆
border-radius: 10px; :绘画圆角矩形
border: 1px gray dashed; :设置边框为间隔为1px的灰色虚线
font-size: 20px; :按钮字体大小为20px
margin-left: 10px; :设置框内字体据框左边为20px
*/
button{
width: 100px;
height: 40px;
border-radius: 10px;
border: 1px gray dashed;
font-size: 20px;
margin-left: 10px;
}
/*
button:hover{} :标签选择器,对所有的button标签控件进行修饰
cursor: pointer;:设置当鼠标光标悬浮在所有button控件上时,都显示小手 -->
*/
button:hover{
cursor: pointer;
}
</style>
</head>
1.3 Js部分
主要任务: 使用jQuery获取前端用户输入的数据,并提交给控制器
(1) 配置jQuery
- 在resources目录下的static文件夹创建jquery文件夹,将jquery函数库文件放入其中
- ReBuild一次项目,此项目才会加载jQuery函数库
(2) 编码
在body标签中编写,在Html界面部分之后编写即可,注意Js部分都需要在script标签中写
<!-- 引入jquery -->
<script src="jquery/jquery-3.6.0.min.js"></script>
<!-- 编写jquery脚本 -->
<script>
jQuery(
function () {
// 这里是java语言
// 使用jQuery找id为btnReg的控件,找的就是注册按钮
// .click():给注册按钮添加click事件,即点击后对应按钮后触发click的事件,
// click事件的具体内容我们自己定义,这里click事件就是获取页面提交的信息
jQuery("#btnReg").click(function () {
//获取页面数据-----------------------------------------------
//对于input标签的输入控件,通过定位 id 就直接获取对应控件得到的数据
var userName = jQuery("#userName").val();
var userPwd = jQuery("#userPwd").val();
var rePwd = jQuery("#rePwd").val();
var userRealName = jQuery("#userRealName").val()
var userEmail = jQuery("#userEmail").val();
// // 特殊处理 单选项择按钮
// // (我们按钮设定;选择男前端返回数值 1,选择女前端返回数值 2)
// // 方法一:
// // 先默认为男,即数值 1
// var uerSex="1";
// // 如果 id 为 girl 的按钮控件被选中,则修改为 2,即选择女数值为 2
// if (jQuery("#girl").checked()){
// userSex="2";
// }
// 方法二:直接获取radio中被选中的那个按钮的值(适用于只有一种单选项按钮的情况,如果除了男女,还有一种选择职业的单选项,那就不可用方法二了)
var userSex = jQuery("input:radio:checked").val();
// 另一种写法:找 input 控件中 name 为 userSex 的按钮(前提是input里有写name属性),根据它的选中值来获取
// var userSex = jQuery("input[name='userSex']:checked").val();
// 在控制台显示我们得到的数据
console.log(userName);
console.log(userSex);
console.log(userPwd);
//向控制台提交数据-----------------------------------------------
//构建json(javaScript对象)格式的数据
//"后端参数名":jQuery变量名 , :引号里对应的是后端的参数名,冒号后是我们定义的获取页面数据的变量名
var user={
"userName":userName,
"userPwd":userPwd,
"userSex":userSex,
"userRealName":userRealName,
"userEmail":userEmail
}
// 往后台发送请求 ajax,提交数据
// jQuery.post("url",json_data,function(rst)):
// url是需要传送到的控制器的路径,这里是将json格式的user数据提交到user控制器的reg方法中去,这里应该先创建控制器,配置好路径,才能写url,不过也可以在这里编好url,创建控制器时命名一致即可
// Json_data:就是传送的json数据,这里写user
// function(rst):其中rst,就是控制器接受数据后反馈的值
jQuery.post("user/reg",user,function (rst) {
// // 向控制台输出rst,就可以知道我们提交成功与否
console.log(rst);
// 如果rst等于1表示控制器成功接受参数
if(rst==1)
{
//向前端网页弹出窗口提示注册成功
alert("注册成功");
}
});
});
})
</script>
2. 创建控制器
2.1 创建文件
在controller包中创建Java class文件
2.2 编写控制器
主要是声名注解、配置前端提交路径,以及编写个方法接受前端传递来的参数
package com.upc.oa.controller;
import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.service.UserInfoService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
// 声名注解
// 配置路径 /user
@RestController
@RequestMapping("/user")
public class UserController {
// 配置路径 /reg
// Html文件将数据提交到reg方法的参数dto中,
@RequestMapping("/reg")
public int reg(UserinfoDto dto){
// 此时我们向前端返回 1,表示控制器成功接收到前端提交的数据
return 1;
}
}
3. 创建业务逻辑
业务逻辑的必要性: 业务逻辑存在的主要原因:我们从前端接受的数据是没有处理过的数据,而后端由于涉及SQL语句,若所有数据都在后端进行整合处理就很麻烦,所以我们在前端和后端中增加了一层处理,这层可以用 Java 语言进行处理,这层处理称为“业务逻辑/业务处理”,可以理解为中端,所以业务逻辑也是整个项目最复杂的部分。
整个项目呈现总-分-总模式: 前端获得总的数据,中端将数据分类处理,后端获得总的处理结果对数据库进行操作
3.1 创建接口
(1) 创建文件
在service包下创建Java class,命名为UserInfoService,这是业务逻辑的函数接口文件
(2) 编写接口
我们只需要编写接受数据的接口,详细处理可以在另一个文件详细写
package com.upc.oa.service;
import com.upc.oa.dto.UserinfoDto;
public interface UserInfoService {
// 编写个函数接口,接受控制器得到的前端数据
int doReg(UserinfoDto dto);
}
3.2 创建业务逻辑
(1) 创建业务逻辑package
在service里创建impl(service implement即服务实施,就是业务逻辑)
(2) 创建业务逻辑文件
- 选择我们刚才的接口,创建业务逻辑
- 将文件存放在业务逻辑包
- 选择要实现的函数接口
- 效果如下:
(3) 编写业务逻辑
package com.upc.oa.service.impl;
import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.mapper.UserinfoMapper;
import com.upc.oa.service.UserInfoService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
// 注解,声名这是业务逻辑
@Service
public class UserInfoServiceImpl implements UserInfoService {
// 声名要对哪个映射文件进行操作
@Resource
private UserinfoMapper userinfoMapper;
// 控制器的数据提交到参数dto
@Override
public int doReg(UserinfoDto dto) {
// 由于我们注册界面数据简单,可以直接转交给后端,
// 所以这里对数据不做处理,直接将数据提交到后端的save函数接口,操作数据库
return userinfoMapper.save(dto);
}
}
(4) 编写控制器
原本控制器接受参数后,仅给前端反馈数据 1,没有将数据传递给中端,现在中端(业务逻辑)编写完成,我们将数据提交到中端
package com.upc.oa.controller;
import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.service.UserInfoService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 声名注解
@RestController
// 配置路径 /user
@RequestMapping("/user")
public class UserController {
// 声名我们调用的数据源
@Resource
private UserInfoService userInfoService;
// 配置路径 /reg
@RequestMapping("/reg")
// Html文件将数据提交到reg方法的参数dto中,
public int reg(UserinfoDto dto){
// 此时我们需要将数据继续提交到业务逻辑中去,所以调用业务逻辑的doReg方法接受参数
return userInfoService.doReg(dto);
}
}
四、运行
1. 启动主程序
2. 进入界面
我们进入login.html界面即可(注意注册重复的用户后台会报错)