1.创建项目
记得将project type改为maven
将需要的包引入其中
更改版本号
引入MYSQL相关包记得进行配置!!!
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
2.前端页面的存放及测试
2.1 前端页面的存放
放到该路径下!!!
2.2 前端页面的测试
启动服务器,测试接口!!!
成功!!!
3.用户接口定义
需求分析
后端需要提供两个服务
1. 提交留言: 用户输⼊留⾔信息之后, 后端需要把留⾔信息保存起来(传参)
2. 展⽰留言: 页面展示时, 需要从后端获取到所有的留⾔信息(相应)
接⼝定义
1. 获取全部留⾔
全部留⾔信息, 我们⽤List来表⽰, 可以⽤JSON来描述这个List数据.
请求:GET /message/getList
响应: JSON 格式
[
{
"from": "⿊猫",
"to": "⽩猫",
"message": "喵"
},{
"from": "⿊狗",
"to": "⽩狗",
"message": "汪"
},
//...
]浏览器给服务器发送⼀个 GET /message/getList 这样的请求, 就能返回当前⼀共有哪些留⾔
记录. 结果以 json 的格式返回过来2. 发表新留言
请求: body 也为 JSON 格式POST /message/publish
{
"from": "⿊猫",
"to": "⽩猫","message": "喵"
}响应: JSON 格式.
{
ok: 1
}我们期望浏览器给服务器发送⼀个 POST /message/publish 这样的请求, 就能把当前的留⾔提交给服务器.
4.服务器代码的实现
4.1 留言对象类
package com.example.demo.model;
import lombok.Data;
@Data
public class MessageInfo {
private String from;
private String to;
private String message;
}
规范代码,使用三层架构!!!
使⽤List<MessageInfo> 来存储留⾔板信息
4.2 Controller类,主要代码
package com.example.demo;
import com.example.demo.model.MessageInfo;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/message")
public class controller {
private List<MessageInfo> messageInfos=new ArrayList<>();//存放前端返回的数据
//将所有存放的数据返回
@RequestMapping("/getList")
public List<MessageInfo> getList() {
return messageInfos;
}
//留言板相关操作,需要验证留言板操作是否正确,不为空时才能提交正确
@RequestMapping("/publish")
public boolean publish(MessageInfo messageInfo) {
System.out.println(messageInfo);
if (StringUtils.hasLength(messageInfo.getFrom())
&& StringUtils.hasLength(messageInfo.getTo())
&& StringUtils.hasLength(messageInfo.getMessage())) {
messageInfos.add(messageInfo);
return true;
}
return false;
}
}
4.3 测试接口
先添加数据,再获取数据,即先测试/publish接口再测试/getList接口
测试成功!!!接口正确!!!
5.前后端交互
修改前端代码
1. 添加 load 函数, ⽤于在⻚⾯加载的时候获取数据(一进来就直接执行这个接口)
相当于Java中的定义函数,定义了需要调用才行。
load();
function load() {
$.ajax({
type: "get",
url: "/message/getList",
success: function (result) {
for (var message of result) {
var divE = "<div>" + message.from + "对" + message.to + "说:" + m
$(".container").append(divE);
}
}
});
}
2.点击提交按钮出发的submit()
function submit(){
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from== '' || to == '' || say == '') {
return;
}
$.ajax({
type: "post",
url: "/message/publish",
data: {
from: form,
to: to,
message: say
// 注意变量要与前端定义一致,否则前端拿不到变量数据
},
success: function(result){
if(result==true){
//添加成功
//2. 构造节点
var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else{
alert("你输入有误哦!!!")
}
}
});
}
5.1 测试
前端代码测试无反应,开始排除错误!!!
前端和后端接口测试无误!!
考虑前后端交互有问题!!!
经过检查右侧拼写有误
同时我发现我们输入空值没有反应
我们发现是由于我们加入了该语句
删除,重新测试!!!
成功!!!
完整前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>留言板</title>
<style>
.container {
width: 350px;
height: 300px;
margin: 0 auto;
/* border: 1px black solid; */
text-align: center;
}
.grey {
color: grey;
}
.container .row {
width: 350px;
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
}
.container .row input {
width: 260px;
height: 30px;
}
#submit {
width: 350px;
height: 40px;
background-color: orange;
color: white;
border: none;
margin: 10px;
border-radius: 5px;
font-size: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>留言板</h1>
<p class="grey">输入后点击提交, 会将信息显示下方空白处</p>
<div class="row">
<span>谁:</span> <input type="text" name="" id="from">
</div>
<div class="row">
<span>对谁:</span> <input type="text" name="" id="to">
</div>
<div class="row">
<span>说什么:</span> <input type="text" name="" id="say">
</div>
<input type="button" value="提交" id="submit" onclick="submit()">
<!-- <div>A 对 B 说: hello</div> -->
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
load();
function load() {
$.ajax({
type: "get",
url: "/message/getList",
success: function(result) {
for (var message of result) {
var divE = "<div>" + message.from + "对" + message.to + "说:" + message.message+"<div>";
$(".container").append(divE);
// 想在class底下添加这条语句
}
}
});
}
function submit(){
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
$.ajax({
type: "post",
url: "/message/publish",
data: {
from: from,
to: to,
message: say
// 注意变量要与前端定义一致,否则前端拿不到变量数据
},
success: function(result){
if(result==true){
//添加成功
//2. 构造节点
var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else{
alert("你输入有误");
}
}
});
}
</script>
</body>
</html>
5.2 前端修饰
6.应用分层
6.1 介绍
阿⾥开发⼿册中, 关于⼯程结构部分, 定义了常⻅⼯程的应⽤分层结构:
- 那么什么是应⽤分层呢?
应⽤分层 是⼀种软件开发设计思想, 它将应⽤程序分成N个层次, 这N个层次分别负责各⾃的职责, 多个
层次之间协同提供完整的功能. 根据项⽬的复杂度, 把项⽬分成三层, 四层或者更多层.
常⻅的MVC设计模式, 就是应⽤分层的⼀种具体体现.
- 为什么需要应⽤分层?
在最开始的时候,为了让项⽬快速上线,我们通常是不考虑分层的. 但是随着业务越来越复杂,⼤量的
代码混在⼀起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动⼀处就牵⼀发⽽动全⾝等
问题. 所以学习对项⽬进⾏分层就是我们程序员的必修课了.
- 如何分层(三层架构)
⽬前现在更主流的开发⽅式是 "前后端分离" 的⽅式, 后端开发⼯程师不再需要关注前端的实现, 所以对于Java后端开发者, ⼜有了⼀种新的分层架构: 把整体架构分为表现层、业务逻辑层和数据层. 这种分层⽅式也称之为"三层架构".1. 表现层: 就是展⽰数据结果和接受⽤⼾指令的,是最靠近⽤⼾的⼀层;(controller)
2. 业务逻辑层: 负责处理业务逻辑, ⾥⾯有复杂业务的具体实现;(service)
3. 数据层: 负责存储和管理与应⽤程序相关的数据(dao/mapper和model)
可以看到, 咱们前⾯的代码, 并不符合这种设计思想, ⽽是所有的代码堆砌在⼀起
我们一般用:
model包:存放信息类的代码
mapper包:存放数据库的相关操作
service:调用mapper包的数据,主要进行业务逻辑的处理!!!
controller:用前端进行交互,调用service包的数据,进行参数的考察和结果的处理
EG:
这三个部分, 在Spring的实现中, 均有体现:
MVC 和三层架构的区别和联系
关于⼆者的关系, ⼀直存在不同的观点. 有⼈认为三层架构是MVC模式的⼀种实现, 也有⼈认为MVC是 三层架构的替代⽅案, 等等各种说法都有. 根本原因是⼤家站在不同的⻆度来看待这个问题的.⼆者其实是从不同⻆度对软件⼯程进⾏了抽象.MVC模式强调数据和视图分离, 将数据展⽰和数据处理分开, 通过控制器对两者进⾏组合.三层架构强调不同维度数据处理的⾼内聚和低耦合, 将交互界⾯, 业务处理和数据库操作的逻辑分开.⻆度不同也就谈不上互相替代了,在⽇常的开发中可以经常看到两种共存的情况,⽐如我们设计模型层的时候往往也会拆分出业务逻辑层(Service层)和数据访问层(Dao层)。但是⼆者的⽬的是相同的, 都是"解耦,分层,代码复⽤"
6.1 代码重构
6.1.1 建包和类
6.1.2 代码拆分
思想:controller调用service,service调用mapper/model
(1)MessageInfo包
package com.example.demo.model;
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
@Component
public class MessageInfo {
private String from;
private String to;
private String message;
}
MessageService包
package com.example.demo.service;
import com.example.demo.model.MessageInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
@Service
public class MessageService {
@Autowired
private MessageInfo messageInfo;
List<MessageInfo> messageInfos=new ArrayList<>();
public List<MessageInfo> getMessagelist(){
return messageInfos;
}
}
MessageController包
package com.example.demo.controller;
import com.example.demo.model.MessageInfo;
import com.example.demo.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/message")
public class MessageController {
@Autowired
private MessageService messageService;
@Autowired
private MessageInfo messageInfo;
//将所有存放的数据返回
@RequestMapping("/getList")
public List<MessageInfo> getList() {
return messageService.getMessagelist();
}
//留言板相关操作,需要验证留言板操作是否正确,不为空时才能提交正确
//留言板相关操作,需要验证留言板操作是否正确,不为空时才能提交正确
@RequestMapping("/publish")
public boolean publish(MessageInfo messageInfo) {
System.out.println(messageInfo);
if (StringUtils.hasLength(messageInfo.getFrom())
&& StringUtils.hasLength(messageInfo.getTo())
&& StringUtils.hasLength(messageInfo.getMessage())) {
messageService.getMessagelist().add(messageInfo);
return true;
}
return false;
}
}
6.1.3 重新测试
(1)后端测试
(2)前端测试
此时还有一个问题,我们前端发送的数据当服务器重启后便会丢失,我们想让他一直存在,考虑引入数据库!!!
7.引入JDBC
我们上面写了表⽩墙,
但是⼀旦服务器重启,
数据仍然会丢失.
要想数据不丢失, 需要把数据存储在数据库中.
接下来借助MyBatis来实现数据的操作
7.1 数据准备
借助Navicat完成数据库准备相关操作
//必须要use 数据库;
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使数据数据
USE mybatis_test;
-- 创建表
DROP TABLE IF EXISTS message_info;
CREATE TABLE `message_info` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`from` VARCHAR ( 127 ) NOT NULL,
`to` VARCHAR ( 127 ) NOT NULL,
`message` VARCHAR ( 256 ) NOT NULL,
`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
ON UPDATE now(): 当数据发生更新操作时, 自动把该列的值设置为now(),
now() 可以替换成其他获取时间的标识符, ⽐如: CURRENT_TIMESTAMP(), LOCALTIME()等
MySQL <5.6.5
1. 只有TIMESTAMP⽀持⾃动更新
2. ⼀个表只能有⼀列设置⾃动更新
3. 不允许同时存在两个列, 其中⼀列设置了DEFAULT CURRENT_TIMESTAMP, 另⼀个设置了ON UPDATE CURRENT_TIMESTAMP
MySQL >=5.6.5
1. TIMESTAMP 和DATETIME都⽀持⾃动更新,且可以有多列
7.2 引⼊MyBatis 和 MySQL驱动依赖
直接generator-editstarter引入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
7.3 配置MySQL账号密码
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
username: root
password: 123456
# 密码要改成自己的密码
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration: # 配置打印 MyBatis⽇志
map-underscore-to-camel-case: true #配置驼峰⾃动转换
7.4 编写后端代码
//此处要与我们的数据库一一对应哦!!
7.4.1 Model包
7.4.1.1 MessageInfo
package com.example.demo.model;
import lombok.Data;
import org.springframework.stereotype.Component;
import java.util.Date;
@Data
@Component
public class MessageInfo {
private Integer id;
private String from;
private String to;
private String message;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
7.4.2 Mapper包(数据库相关操作)
//我们一共要满足两个操作
7.4.2.1 查询操作
//1.查
@Select("select 'id','from','to','message' from message_info where deleteFlag=0")
List<MessageInfo> queryAll();
7.4.2.2 增加操作
//2.增
//2.增
@Insert("insert into message_info('from','to','message') values (#{from},#{to},#{message})")
Integer insetInfo();
7.4.2.3 测试
@SpringBootTest
class MessageInfoMapperTest {
@Autowired
private MessageInfoMapper messageInfoMapper;
@Test
void queryAll() {
List<MessageInfo> messageInfos=messageInfoMapper.queryMessageList();
}
@Autowired
private MessageInfo messageInfoss;
@Test
void insetInfo() {
messageInfoss.setFrom("a");
messageInfoss.setMessage("b");
messageInfoss.setTo("111");
messageInfoMapper.insertMessage(messageInfoss);
}
}
测试通过!!!
查询数据库
增加成功!!!
7.4.3 Service包
package com.example.demo.service;
import com.example.demo.mapper.MessageInfoMapper;
import com.example.demo.model.MessageInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
@Service
public class MessageService {
@Autowired
private MessageInfoMapper messageInfoMapper;
public List<MessageInfo> queryMessageList(){
return messageInfoMapper.queryMessageList();
}
public Integer addMessage(MessageInfo messageInfo){
return messageInfoMapper.insertMessage(messageInfo);
}
}
7.4.4 Controller包
package com.example.demo.controller;
import com.example.demo.model.MessageInfo;
import com.example.demo.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/message")
public class MessageController {
@Autowired
private MessageService messageService;
@Autowired
private MessageInfo messageInfo;
//将所有存放的数据返回
@RequestMapping("/getList")
public List<MessageInfo> getList() {
return messageService.queryMessageList();
}
//留言板相关操作,需要验证留言板操作是否正确,不为空时才能提交正确
//留言板相关操作,需要验证留言板操作是否正确,不为空时才能提交正确
@RequestMapping("/publish")
public boolean publish(MessageInfo messageInfo) {
System.out.println(messageInfo);
if (StringUtils.hasLength(messageInfo.getFrom())
&& StringUtils.hasLength(messageInfo.getTo())
&& StringUtils.hasLength(messageInfo.getMessage())) {
messageService.addMessage(messageInfo);
return true;
}
return false;
}
}
7.5 测试后端接口
127.0.0.1:8080/message/getList
http://127.0.0.1:8080/message/publish?from=12211&to=222&message=322
成功!!!
7.6 测试前后端交互
成功!!!