项目3-留言板

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 站在后端开发⼈员的⻆度上, 也进⾏了⽀持, 把上⾯的代码划分为三个部分:
请求处理、响应数据:负责,接收⻚⾯的请求,给⻚⾯响应数据.(controller)
逻辑处理:负责业务逻辑处理的代码.(service)
数据访问:负责业务数据的维护操作,包括增、删、改、查等操作.(mapper/model)

 这三个部分, 在Spring的实现中, 均有体现:

Controller:控制层。接收前端发送的请求,对请求进⾏处理,并响应数据。
Service:业务逻辑层。处理具体的业务逻辑。
Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查

MVC 和三层架构的区别和联系

关于⼆者的关系, ⼀直存在不同的观点. 有⼈认为三层架构是MVC模式的⼀种实现, 也有⼈认为MVC是 三层架构的替代⽅案, 等等各种说法都有. 根本原因是⼤家站在不同的⻆度来看待这个问题的.
⼆者其实是从不同⻆度对软件⼯程进⾏了抽象.
MVC模式强调数据和视图分离, 将数据展⽰和数据处理分开, 通过控制器对两者进⾏组合.
三层架构强调不同维度数据处理的⾼内聚和低耦合, 将交互界⾯, 业务处理和数据库操作的逻辑分开.
⻆度不同也就谈不上互相替代了,在⽇常的开发中可以经常看到两种共存的情况,⽐如我们设计模型层的时候往往也会拆分出业务逻辑层(Service层)和数据访问层(Dao层)。
但是⼆者的⽬的是相同的, 都是"解耦,分层,代码复⽤"

 

MVC中, 视图和控制器合起来对应三层架构中的表现层(controller). 模型对应三层架构中的业务逻辑层(service), 数据层(mapper/dao), 以及实体类(model)

 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 测试前后端交互

成功!!! 

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值