Springboot 前后端分离项目中遇见的一个小问题

在springboot前后端分离项目中遇见前端代码不能刷新的问题

在学习springboot前后端分离项目时,参照教程1简单实现了一个前后端登录页面。

教程1其实是一个伪前后端分离项目,但是对我们理解前后端分离项目的开发有一定的意义。

虽然具体的开发过程和项目结果和教程中的类似,但是作为项目记录,我还是想将我所有的开发流程在这里重写一遍,并将遇见的问题一一列举出来,作为一个记录。

1. 创建数据库表结构

在这里插入图片描述

表结构如图,基本就是一个登陆/注册的基本信息收集

2. 创建Springboot项目

​ 本项目的构建过程如下:本项目使用IDEA作为主要开发工具,构建过程如下

​ 2.1 创建新项目

在这里插入图片描述

2.2 使用Spring Initializr 构建springboot项目
在这里插入图片描述

​ 如果选择的是Spring构建的就是spring项目而非springboot项目

​ 这里,SDK选择本地的java版本,Initializr Server URL默认就像,确保网速稳定即可。【也可以选择Custom但是我没有使用过,具体可以查查网上的使用教程】

2.3 选择版本
在这里插入图片描述

这里Group和Artifact就是项目名称了,后期创建项目文件夹会以Artifact的名字创建,里面不要包含特殊字符就行

Type类型默认就行,

Language默认,

Packaging是选择打包模式,一般有jar和war。默认就行

JavaVersion,选择本地java版本就行,我选择8,这里默认是IDEA自带的版本

其他的内容默认就行,因为这是一个测试项目而非正式项目,所以大部分内容都是默认即可

2.4 选择依赖内容

在这里插入图片描述

因为这是一个前后端分离项目,所以我没有选择模板引擎的内容,如果选择了模板引擎一般使用的是Thymeleaf

这里 数据库选择的是Mysql,数据库操作框架选择是Mybatis.

因为是一个web应用,因此选择的了Springweb。

一般我们可能还需要选择Spring Devtools以用来进行热启动选项。

选择了上述依赖后,点击下一步

2.5 选择项目位置,创建项目

在这里插入图片描述

3 项目结构

项目结构如图所示

在这里插入图片描述

因为我是用的是Mybatis框架操作的数据库内容,因此这里需要一个针对Mybatis的xml配置文件用来操作数据。

特别说明:】不同于eclipse,在IDEA中,我们需要将xml文件存放在resources文件夹中,而不能存在java文件中,不然无论你在application.properties如何配置mybatis的xml文件搜索路径都无法将xml文件编译到target目录内。这是因为IDEA默认希望所有的资源文件都在Resources目录下,java文件内只用写代码即可。也算是一个小坑吧。

4 具体代码

4.1 POJO包

4.1.1 User类

​ 构建User类,完成对数据库的映射,以及完成对前端数据的接受工作

​ User类的内容如下:

package com.example.springbootdemoforweb2.Pojo;

/**
 * 一个pojo类
 */
public class User {

    private int id;
    private String name;
    private String passwd;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}
4.1.2 构建后端返回给前端的数据结构类Result

​ Result类用于构建一个数据结构,这个结构包含了后端返回给前端的数据,将其组织起来,然后依据Controller层的@ResponseBody注解,将处理结果包装成json对象,返回给前端页面.完成对前后端数据的交互.

package com.example.springbootdemoforweb2.Pojo;

/**
 * 定义后端向前端发送的数据结构
 */
public class Result<T> { // 这里T代表可以返回任意数据类型

    private String msg;
    private boolean success;
    private T detail;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public T getDetail() {
        return detail;
    }

    public void setDetail(T detail) {
        this.detail = detail;
    }
}

4.2 Mapper层

4.2.1 构建UserMapper 接口,定义数据库操作方法
package com.example.springbootdemoforweb2.Mapper;

import com.example.springbootdemoforweb2.Pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 构造UserMapper 操控数据库
 */
@Mapper
@Repository
public interface UserMapper {

    public List<User> findAll();
    public User findByName(User user);
    public int delete(User user);
    public void put(User user);
    public Integer login(User user); // 这里使用Interger而不是Int是因为返回结果可能为空
    public void regis(User user);
}

​ 这里是一个接口 不需要实例化,Springboot会自动实例化这个接口并完成相关功能。因此我们只需要定义一个接口即可。

​ 这里需要注意的是,我们不仅在UserMapper上使用了@Mapper注解,也使用了@Repository注解,之所以使用@Repository注解是因为在service层自动注入UserMapper对象时可能会报错,具体原因目前还没有弄清楚,有待观察。

4.3 Service层

4.3.1 在构建好Mapper层后,构建Service层完成相关具体的服务工作
package com.example.springbootdemoforweb2.Service;

import com.example.springbootdemoforweb2.Mapper.UserMapper;
import com.example.springbootdemoforweb2.Pojo.Result;
import com.example.springbootdemoforweb2.Pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 服务提供方
 */
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public Result login(User user){

        Result result = new Result();
        result.setSuccess(false);
        result.setDetail(null);

        try {

            Integer id = userMapper.login(user);

            if (id!=null){
                // 代表查找成功
                result.setSuccess(true);
                result.setMsg("登录成功");
                result.setDetail(userMapper.findByName(user));
            }else{
                result.setMsg("登录失败,该用户或者密码错误");
            }


        }catch (Exception e){
            result.setMsg(e.getMessage());
            e.printStackTrace();
        }

        return result;

    }

    public Result registry(User user){

        Result result = new Result();
        result.setSuccess(false);
        result.setDetail(null);

        try {

            User exituser = userMapper.findByName(user);
            if (exituser!=null){
                //当该用户名已经存在,返回注册失败
                result.setMsg("该用户名已经存在");
            }else {
                userMapper.regis(user);
                result.setSuccess(true);
                result.setMsg("注册成功");
                result.setDetail(userMapper.findByName(user));
            }

        }catch (Exception e){
            result.setMsg(e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

}

4.4 Mybatis配置文件

4.4.1 构建UserMapper.xml配置文件
<?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.example.springbootdemoforweb2.Mapper.UserMapper">

    <!--        查找所有内容-->
    <select id="findAll" resultType="User">
            select * from user_info
        </select>

    <select id="findByName" parameterType="User" resultType="User">
            select * from user_info where name = #{name}
        </select>

    <select id="login" parameterType="User" resultType="int">
            select id from user_info where name=#{name} and passwd=#{passwd}
        </select>

    <insert id="regis" parameterType="User" >
            insert into user_info (name,passwd) values (#{name},#{passwd})
        </insert>

    <delete id="delete" parameterType="User">
            delete from user_info where name = #{name} and passwd = #{passwd}
        </delete>

    <update id="update" parameterType="User">
            update user_info set passwd = #{passwd} where name=#{name}
        </update>


</mapper>

​ 这里,我们构建一个UserMapper.xml的配置文件,该文件是Mybatis的核心配置文件。其中namespace需要只想UserMapper这个借口,需要使用全局限定名称。然后再标签内写下所有操作数据库的方法。其中id就是UserMapper的方法名

4.5 Controller层

4.5.1 构建UserController完成功能映射
package com.example.springbootdemoforweb2.Controller;

import com.example.springbootdemoforweb2.Pojo.Result;
import com.example.springbootdemoforweb2.Pojo.User;
import com.example.springbootdemoforweb2.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    @ResponseBody
    public Result login(User user){
        System.out.println("用户姓名:"+user.getName()+"\t用户密码:"+user.getPasswd());
        return userService.login(user);
    }

    @RequestMapping("/registry")
    @ResponseBody
    public Result regis(User user){
        return userService.registry(user);
    }


}

​ 功能映射配置很简单,这里使用@ResponseBody将函数的方法转换为json格式

​ 如果使用了Thymeleaf,并将@ResponseBody删除,在propertis配置文件中指定了默认网页地址,就可以通过返回的名称直接定位到指定的网页中。不过这个是前后端不分离的做法。

​ 在前后端分离的开发过程中,前后端一般通过json传递数据内容。因此这里可以通过配置@ResponseBody将返回的Result类型构造为Json格式

4.6 application.properties配置文件

# mysql配置
spring.datasource.url=jdbc:mysql://localhost:3306/zyc_web_test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5

# 端口配置
server.port=9090

# 静态资源配置
spring.resources.static-locations=classpath:/static

# 配置mybatis环境
mybatis.type-aliases-package=com.example.springbootdemoforweb2.Pojo
mybatis.mapper-locations=classpath:MapperXML/*.xml

该配置文件是springboot的核心配置文件,通过该配置文件可以设定springboot项目的各种信息。

这里我们需要注意到的是mybatis环境配置信息,其中mapper-locations配置了xml问津的路径,type-aliases-package配置了xml文件类resultType的简写路径。

其他的像Mysql配置,端口配置,静态资源配置就很容易理解了

4.7 静态文件

4.7.1 登录页面 login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <form action="/login" method="post">
        <p>用户名:<input name="name" type="text"></p>
        <p>密码:<input name="passwd" type="password"></p>
        <input type="submit" value="登录">
    </form>
</body>
</html>

这里是登录页面,因为这是一个简单地前后端分离登录页面,因此前端项目没有单独使用一个服务器部署

4.7.2 注册页面registry.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>

    <form action="/registry" method="post">
        <p>用户名:<input name="name" type="text"></p>
        <p>密码:<input name="passwd" type="password"></p>
        <input type="submit" value="注册">
    </form>

</body>
</html>

这里是注册页面

5 遇见的问题

其实,一开始登录页面以及注册页面中表格代码不是如上所示的内容,其初始内容如下:

注册页面
<form action="/registry" method="post">
    <p>用户名:<input name="username" type="text"></p>
    <p>密码:<input name="passwd" type="password"></p>
    <input type="submit" value="注册">
</form>

这里用户名的name属性是username,而不是完成版中的name。需要注意的是前端通过POST方法向后端提交数据时,后端可以通过getparameter方法获取指定name属性的值。而一开始,name属性的值是username而非User对象中的name,导致后端无法正确接收用户姓名。

​ 当将前端的name属性修改为name后发现还是无法正确接收用户姓名属性。在target编译文件中可以发现login.html和registry.html中相关属性已经修改成功。最后在chrome中发现,原来是chrome的缓存机制导致修改后的网页并没有立刻呈现出修改后的结果,其name属性仍然是username而非name

​ 其解决方法如下:

  1. 点击F12打开开发者模式

  2. 点击右上角的三个点

  3. 在这里插入图片描述

  4. 点击设置

  5. 在这里插入图片描述

  6. 点击

  7. 在这里插入图片描述
    点击如上两个选项,让chrome缓存失效,保证每一次的页面都是最新的页面即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值