SpringBoot项目实战记录

SpringBoot项目实战记录

1:项目初始化

(1)新建项目

(2)给pox.xml添加依赖

首先就是添加项目下载仓库为阿里云仓库

<repositories>
    <repository>
        <id>nexus-aliyun</id>
        <name>nexus-aliyun</name>
        <url>http://aliyun.com/nexus/content/groups/public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>public</id>
        <name>aliyun nexus</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>

并且在dependencies下添加baomidou

 <!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

(3)编写配置文件application.yml

springBoot工程中是有一个application.yml配置文件的啊,其实application.yml的功能和application.properties是一样的,不过因为yml文件是树状结构,写起来有更好的层次感,更易于理解,所以很多人都选择了yml文件。

server:
// 修改端口为9090端口
  port: 9090

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    // ?serverTimezone=GMT%2b8表示时区为东八区
    url: jdbc:mysql://localhost:3306/party_building?serverTimezone=GMT%2b8
    username: root
    password: 528957

2:初步编写Mybatis

(1)添加实体entity

所有的实体类需要加上如下注释

@Data : 注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法

@AllArgsConstructor : 注在类上,提供类的全参构造

@NoArgsConstructor : 注在类上,提供类的无参构造

比如现在对于一个党建信息的实体类(com/example/entity/PartyInf.java)

package com.example.entity;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PartyInf {
    
    
    //  序号0
//    @TableId(type = IdType.AUTO)
    private Integer id;
    //  市(州)1
    private String shi;
    ......
    //  创建时间
    private LocalDateTime create_time;
}

(2)添加Mapper接口

重点就是这个mapper或者有些人命名为dao的接口需要一个@Mapper的注释声明这是一个mapper接口,如果使用mybatis这个接口时直接对接sql语句的。

(com/example/Mapper/PartyInfMapper.java)

package com.example.mapper;

import com.example.entity.PartyInf;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface PartyInfMapper {
    
    
    @Select("select * from party_inf")
    List<PartyInf> findAll();
}

但是现在这个没有被SpringBoot所管理,呗SpringBoot管理的都必须要有@Conponent

(3)添加控制器类Controller

控制器类主要就是使用@RestController声明这是一个控制器,然后使用 @Autowired调用Mapper里的方法。

package com.example.controller;

import com.example.entity.PartyInf;
import com.example.mapper.PartyInfMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class PartyInfController {
    
    
    @Autowired
    private PartyInfMapper partyInfMapper;

    @GetMapping("/party/findAll")
    public List<PartyInf> findAll(){
    
    
        return partyInfMapper.findAll();
    }
}

(4)服务类Service

加一个Service

Service需要注解@Service,和@Mapper一样需要这个注解把这个类注入到SpringBoot的容器内

package com.example.service;


import com.example.entity.PartyInf;
import com.example.mapper.PartyInfMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PartyInfService {
    
    
    @Autowired
    private PartyInfMapper partyInfMapper;
}

3:Mybatis实现增删改查

对用户表进行增删改查

首先就是实体类

com/example/entity/UserInf.java

package com.example.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInf {
    
    
    private Integer id;
    private String username;
    private String password;
    private Integer power;
    private String region;
}

之后Mapper数据库操作接口

com/example/mapper/UserInfMapper.java

package com.example.mapper;

import com.example.entity.UserInf;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface UserInfMapper {
    
    

    @Select("select * from user_inf")
    List<UserInf> findAll();
    @Insert("INSERT INTO user_inf(username,password,power,region) VALUES (#{username},#{password},#{power},#{region})")
    int insert(UserInf userInf);
    @Update("UPDATE user_inf SET username=#{username},password=#{password},power=#{power},region=#{region} WHERE id=#{id}")
    int update(UserInf userInf);
    @Delete("DELETE FROM user_inf WHERE id=#{id}")
    int delete(@Param("id") Integer id);
}

Service服务类

com/example/service/UserInfService.java

package com.example.service;

import com.example.entity.UserInf;
import com.example.mapper.UserInfMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfService {
    
    
    @Autowired
    private UserInfMapper userInfMapper;
    public int save(UserInf userInf){
    
    
        if (userInf.getId() == null){
    
    
            return userInfMapper.insert(userInf);
        }else {
    
    
            return userInfMapper.update(userInf);
        }
    }
}

Controller控制器类

com/example/controller/UserInfController.java

package com.example.controller;

import com.example.entity.UserInf;
import com.example.mapper.UserInfMapper;
import com.example.service.UserInfService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserInfController {
    
    
    @Autowired
    private UserInfMapper userInfMapper;
    @Autowired
    private UserInfService userInfService;

    @GetMapping("/findAll")
    public List<UserInf> findAll(){
    
    
        return userInfMapper.findAll();
    }
    @PostMapping("/save")
    public Integer save(@RequestBody UserInf userInf){
    
    
        System.out.println(userInf);
        return userInfService.save(userInf);
    }
    @DeleteMapping("/delete/{id}")
    public Integer delete(@PathVariable Integer id){
    
    
        return userInfMapper.delete(id);
    }
}

4:SpringBoot解决跨域问题

后端接口写好了前端要用axios进行数据请求还需要配置跨域,跨域分为前端跨域和后端跨域,后端跨域是一种一劳永逸的做法,所以本次开发对后端进行跨域配置。

新建一个config类com/example/config/CorsConfig.java

package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    
    

    // 当前跨域请求最大有效时长。这里默认1天
    private static final long MAX_AGE = 24 * 60 * 60;

    @Bean
    public CorsFilter corsFilter() {
    
    
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://localhost:8080"); // 1 设置访问源地址
        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
        corsConfiguration.setMaxAge(MAX_AGE);
        source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
        return new CorsFilter(source);
    }
}

5:Mybatis-Plus进行实现分页查询

(1)配置Mybatis-Plus

先在pom.xml下的dependencies标签下引入依赖

<!--  mybatis-plus    -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

之后创建一个Mybatis-Plus的Config插件

com/example/config/MybatisPlusConfig.java

package com.example.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
//这个是Mapper层的代码存放目录,之后就可以把Mapper里面的@Mapper注释去掉,这样的好处就是所有的配置统一管理
@MapperScan("com/example/mapper")
public class MybatisPlusConfig {
    
    
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    
    
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor (DbType.MYSQL));
        return interceptor;
    }
}

(2)Mybatis-Plus修改原本的增删改查

首先就是修改mapper,Mybatis-Plus下的mapper需要继承BaseMapper<实体>。

package com.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.UserInf;
import org.apache.ibatis.annotations.*;
import java.util.List;

//@Mapper
public interface UserInfMapper extends BaseMapper<UserInf> {
    
    
    @Select("select * from user_inf")
    List<UserInf> findAll();
    @Insert("INSERT INTO user_inf(username,password,power,region) VALUES (#{username},#{password},#{power},#{region})")
    int insert(UserInf userInf);
    @Update("UPDATE user_inf SET username=#{username},password=#{password},power=#{power},region=#{region} WHERE id=#{id}")
    int update(UserInf userInf);
    @Delete("DELETE FROM user_inf WHERE id=#{id}")
    int delete(@Param("id") Integer id);
}

之后修改服务类,Mybatis-Plus自带了一个save方法,所以原本的sava方法就不用了

package com.example.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.UserInf;
import com.example.mapper.UserInfMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfService extends ServiceImpl<UserInfMapper,UserInf> {
    
    
    public boolean saveUserInf(UserInf userInf){
    
    
        return saveOrUpdate(userInf);
    }
}

其他的都可以不变

分页查询代码

5:Vue使用axios进行api请求

(1)装配axios

先安装axios

yarn add [email protected]

在前端项目的src文件夹下新建一个文件夹utils,之后新建文件request.js,request代码如下

src\utils\request.js

import axios from 'axios'

const request = axios.create({
    
    
      // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在
      //  页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!!
	baseURL: '/api',
    timeout: 5000
})

// request 拦截器(对请求头进行处理)
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    
    
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
  
    // config.headers['token'] = user.token;  // 设置请求头
    return config
}, error => {
    
    
    return Promise.reject(error)
});

// response 拦截器(对响应结果进行处理)
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
    response => {
    
    
        let res = response.data;
        // 如果是返回的文件
        if (response.config.responseType === 'blob') {
    
    
            return res
        }
        // 兼容服务端返回的字符串数据
        if (typeof res === 'string') {
    
    
            res = res ? JSON.parse(res) : res
        }
        return res;
    },
    error => {
    
    
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)

export default request

最后在main.js中引入一下

import request from '@/utils/request'

Vue.prototype.request = request

(2)使用axios进行get和post请求

GET请求

this.request.get("http://127.0.0.1:9090/party/page", {
    
    
    params: {
    
    
        pageNum: this.pageNum,
        pageSize: this.pageSize,
        xxmc: this.xxmc,
        xxlx: this.xxlx,
        dzzszxs: this.dzzszxs,
    }
}).then(res => {
    
    
    this.tableData = res.data.records
    this.total = res.data.total
})

POST请求

this.request.post("http://127.0.0.1:9090/party/save", this.form).then(res => {
    
    
    if (res.data) {
    
    
        this.$message.success("保存成功")
        this.dialogFormVisible = false
        this.load()
    } else {
    
    
        this.$message.error("保存失败")
        this.dialogFormVisible = false
        this.load()
    }
})

DELETE请求

this.request.delete("http://127.0.0.1:9090/party/delete/" + id).then(res => {
    
    
    if (res.data) {
    
    
        this.$message.success("删除成功")
        this.load()
    } else {
    
    
        this.$message.error("删除失败")
        this.load()
    }
})

6:SpringBoot+Vue登录

先写后端嘛

(1)SpringBoot创建接收登录参数的DTO

登录主要就只需要账号密码,在Controller项目包下创建一个项目包名为DTO

创建一个LogoinDto.java,需要#Date参数声明这是一个Date型类,

com/example/controller/dto/LoginDto.java代码如下:

package com.example.controller.dto;

import lombok.Data;

@Data
public class LoginDto {
    
    
    public String username;
    public String password;
}

之后编写登录验证函数

控制器类com/example/controller/UserInfController.java

@PostMapping("/login")
public Result login(@RequestBody LoginDto loginDto){
    
    
    String userneme = loginDto.getUsername();
    String password = loginDto.getPassword();
    if (StringUtils.isBlank(userneme) || StringUtils.isBlank(password)){
    
    
        return Result.error("404","账号或密码不可为空");
    }
    UserInf userInf = userInfService.login(loginDto);
    if (userInf == null){
    
    
        return Result.error("404","账号或密码错误");
    }
    return Result.success(userInfService.login(loginDto));
}

服务类com/example/service/UserInfService.java

public UserInf login(LoginDto loginDto) {
    
    
    QueryWrapper<UserInf> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("username",loginDto.getUsername());
    queryWrapper.eq("password",loginDto.getPassword());
    UserInf userInf = getOne(queryWrapper);
    return userInf;
}

Postman测试一下可行,开始编写前端界面

(2)Vue axios调用登录接口

<template>
  <div id="Login" class="wrapper">
    <div style="margin:200px auto; background-color: #fff; width: 350px; height: 300px; padding: 20px; border-radius: 10px;">
      <div style="margin: 20px 0; text-align: center; font-size: 24px;"><b>Welcome</b></div>
      <el-form :rules="rules" :model="user" ref="userForm">
        <el-form-item prop="username" label="">
          <el-input placeholder="请输入账号" size="medium" style="margin:10px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
        </el-form-item>
        <el-form-item prop="password" label="">
          <el-input placeholder="请输入密码" size="medium" style="margin:10px 0" prefix-icon="el-icon-lock" show-password v-model="user.password"></el-input>
        </el-form-item>
        <div style="margin: 10px 0;text-align:right">
          <el-button type="primary" size="small" autocomplete="off" @click="login">登录</el-button>
        </div>
      </el-form>
    </div>
  </div>
</template>

<script>
name:"Login"
export default {
  data(){
    return{
      adminLogin:'0',
      user: {
        username: "username",
        password: "123456"
      },
      rules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
          { min: 3, max: 20, message: '用户名长度在 6 到 20 个字符', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          { min: 3, max: 20, message: '密码长度在 6 到 20 个字符', trigger: 'blur' }
        ],
      }
    }
  },
  methods:{
    login(){
      this.$refs['userForm'].validate((valid) => {
        if (valid) {
          // 用户登录
          if (this.adminLogin === '0'){
            this.request.post("http://127.0.0.1:9090/user/login", this.user).then(res =>{
              if(res.code === '200'){
                this.$message.success('登录成功,欢迎使用!!!');
            //     localStorage.setItem("user", JSON.stringify(res.data))  // 存储用户信息到前端浏览器
            //     this.$router.push("/Manage/home")
              }else{
                this.$message.error(res.msg);
              }
              console.log(res)
            })
          }
        } else {
          this.$message.error('请以正确的方式输入登录信息!!');
          return false;
        }
      });
      
    }
  }
}
</script>
<style>
  .wrapper{
    height: 100vh;
    background-image: linear-gradient(to bottom right,#FC466B,#3F5EFB);
    overflow: hidden;
  }
</style>

7:SpringBoot集成JWT(Json Web Token)

(1)JWT简介

Jwt全称是:json web token。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。

优点
  1. 简洁: 可以通过URL、POST参数或者在HTTP header发送,因为数据量小,传输速度也很快;
  2. 自包含:负载中可以包含用户所需要的信息,避免了多次查询数据库;
  3. 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持;
  4. 不需要在服务端保存会话信息,特别适用于分布式微服务。
缺点
  1. 无法作废已颁布的令牌;
  2. 不易应对数据过期。

(2)JWT组成

一个token分3部分,按顺序为

  1. 头部(header)
  2. 载荷(payload)
  3. 签证(signature)

三部分之间用“.”号做分隔。

/*不废话了,开始使用Token/

(3)JWT的使用

1)SpringBoot引入jwt

项目依赖pom.xml

<!--JWT-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>
<!--hutool-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.20</version>
</dependency>
2)编写token工具类

先写一个生成token的方法,将用户id作为载荷,用户密码作为密钥生成token

建立一个utils的插件包,创建一个TokenUtils代码如下:
com/example/utils/TokenUtils.java

package com.example.utils;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;

public class TokenUtils {
    
    
    public static String genToken(String userId, String sign) {
    
    
        return JWT.create().withAudience(userId) // 将 userId 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetDay (new Date(), 1)) // 设置1天(offsetDay)后token过期
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
    }
}
3)修改登录的返回值以及方法,把token一起作为返回值的返回到前端

com/example/controller/dto/UserDto.java

package com.example.controller.dto;

import lombok.Data;

@Data
public class UserDto {
    
    
    private Integer id;
    private String username;
    private String password;
    private Integer power;
    private String shi;
    private String xian;
    private String token;
}

com/example/controller/UserInfController.java

@PostMapping("/login")
public Result login(@RequestBody UserDto userDto){
    
    
    String userneme = userDto.getUsername();
    String password = userDto.getPassword();
    if (StringUtils.isBlank(userneme) || StringUtils.isBlank(password)){
    
    
        return Result.error("404","账号或密码不可为空");
    }
    if (userInfService.login(userDto) == null){
    
    
        return Result.error("404","账号或密码错误");
    }
    return Result.success(userInfService.login(userDto));
}

com/example/service/UserInfService.java

public UserDto login(UserDto userDto) {
    
    
    QueryWrapper<UserInf> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("username",userDto.getUsername());
    queryWrapper.eq("password",userDto.getPassword());
    UserInf userInf = getOne(queryWrapper);
    if (userInf == null){
    
    
        return null;
    }else {
    
    
        BeanUtil.copyProperties(userInf,userDto,true);
        userDto.setToken(TokenUtils.genToken(userDto.getId().toString(),userDto.getPassword()));
        return userDto;
    }
}
4)前端在接收到登录时把返回参数保存下来,并且设置登陆之后的请求时带上token

先修改axios的配置文件,utils/request.js

import axios from 'axios'

const request = axios.create({
    
    
      // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在
      //  页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!!
	baseURL: 'http://127.0.0.1:9090',
    timeout: 5000
})

// request 拦截器(对请求头进行处理)
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    
    
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    let user = localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : null
    if(user){
    
    
        config.headers['token'] = user.token;  // 设置请求头
    }
    
    return config
}, error => {
    
    
    return Promise.reject(error)
});

// response 拦截器(对响应结果进行处理)
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
    response => {
    
    
        let res = response.data;
        // 如果是返回的文件
        if (response.config.responseType === 'blob') {
    
    
            return res
        }
        // 兼容服务端返回的字符串数据
        if (typeof res === 'string') {
    
    
            res = res ? JSON.parse(res) : res
        }
        return res;
    },
    error => {
    
    
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)
export default request

之后修改一下登录的login方法。

this.request.post("/user/login", this.user).then(res =>{
    
    
              if(res.code === '200'){
    
    
                this.$message.success('登录成功,欢迎使用!!!');
                localStorage.setItem("user", JSON.stringify(res.data))// 存储用户信息到前端浏览器
                this.$router.push("/")
              }else{
    
    
                this.$message.error(res.msg);
              }
              console.log(res)
            })

if (response.config.responseType === ‘blob’) {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === ‘string’) {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
console.log(‘err’ + error) // for debug
return Promise.reject(error)
}
)
export default request


[外链图片转存中...(img-hs5Hiwcu-1667960992419)]

之后修改一下登录的login方法。

```js
this.request.post("/user/login", this.user).then(res =>{
              if(res.code === '200'){
                this.$message.success('登录成功,欢迎使用!!!');
                localStorage.setItem("user", JSON.stringify(res.data))// 存储用户信息到前端浏览器
                this.$router.push("/")
              }else{
                this.$message.error(res.msg);
              }
              console.log(res)
            })

猜你喜欢

转载自blog.csdn.net/m0_55534317/article/details/127764844