# springbootdemo
**Repository Path**: webrx/springbootdemo
## Basic Information
- **Project Name**: springbootdemo
- **Description**: springboot vue3 项目
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-09-26
- **Last Updated**: 2023-09-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ERP项目开发
项目源码参考:git clone https://gitee.com/webrx/springbootdemo.git
## 后端数据库
```sql
-- 建立数据库
create database dbwx default charset utf8;
use dbwx;
-- 建立临时表,用于存储会话验证码
create table t_captcha(
id char(36) primary key,
value varchar(10),
create_time timestamp default CURRENT_TIMESTAMP on UPDATE CURRENT_TIMESTAMP
)engine=memory;
-- 定义事件1分钟就会删除
create event capdel on schedule every 1 minute
do delete from t_captcha where create_time < adddate(now(),interval -1 minute);
```
## 后端接口
### api后端接口 项目
#### 建立项目2.7.16
> 第一步:pom.xml
>
```xml
4.0.0
org.example
springbootdemo
1.0
ch01hello
17
17
UTF-8
org.springframework.boot
spring-boot-dependencies
2.7.16
pom
import
org.yaml
snakeyaml
2.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
2.7.16
org.projectlombok
lombok
```
#### 建立入口程序App.java
`cn.webrx.App`
```java
package cn.webrx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
```
debug方式启动运行App


#### 编写接口
`cn.webrx.controller.UserController`
```java
package cn.webrx.controller;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping
public String index() {
return SpringBootVersion.getVersion();
}
}
```
#### 浏览接口
`springboot web项目,默认内嵌了tomcat ,端口号为8080`
http://localhost:8080/user

### 建立api项目3.1.4
#### pom.xml
```xml
4.0.0
org.example
springbootdemo
1.0
ch02demo
17
17
UTF-8
org.springframework.boot
spring-boot-dependencies
3.1.4
pom
import
org.yaml
snakeyaml
2.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
3.1.4
org.projectlombok
lombok
```
#### App.java
```java
package cn.webrx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication @RestController
public class App {
@GetMapping("/")
public String version(){
return SpringBootVersion.getVersion();
}
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
```
#### 启动App


### api项目建立
#### pom.xml
```xml
4.0.0
org.example
springbootdemo
1.0
api
17
17
UTF-8
org.springframework.boot
spring-boot-dependencies
2.7.16
pom
import
org.yaml
snakeyaml
2.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
com.baomidou
mybatis-plus-boot-starter
3.5.3.2
mysql
mysql-connector-java
8.0.33
com.auth0
java-jwt
4.4.0
com.alibaba
druid-spring-boot-starter
1.2.19
org.springframework.boot
spring-boot-maven-plugin
2.7.16
org.projectlombok
lombok
```
#### resources/application.yml
```yml
server:
port: 8080
spring:
datasource:
druid:
url: jdbc:mysql:/wxdb
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
password:
```
#### App.java
```java
package cn.webrx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
```
### jwt token
#### 简介
WT:Json Web Token,是基于Json的一个公开规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,他的两大使用场景是:认证和数据交换
使用起来就是,由服务端根据规范生成一个令牌(token),并且发放给客户端。此时客户端请求服务端的时候就可以携带者令牌,以令牌来证明自己的身份信息。
作用:类似session保持登录状态 的办法,通过token来代表用户身份。
#### 生成校验


#### 优点
jwt基于json,非常方便解析可以再令牌中自定义丰富的内容,易扩展(payload可以扩展)通过签名,让JWT防止被篡改,安全性高资源服务使用JWT可不依赖认证服务即可完成授权
#### api token
```xml
com.auth0
java-jwt
4.4.0
```
#### jwt demo
```java
public class JwtDemo {
public static void main(String[] args) {
//jwt 官方网站 https://jwt.io/
String SECRET = "webrx";
HashMap headers = new HashMap<>();
// 过期时间,60s
Calendar expires = Calendar.getInstance();
expires.add(Calendar.SECOND, 3600);
String jwtToken = JWT.create()
.withHeader(headers)// 第一部分Header
.withClaim("userId", 007)// 第二部分Payload
.withClaim("userName", "admin")
.withExpiresAt(expires.getTime())//有效期
.sign(Algorithm.HMAC256(SECRET));// 第三部分Signature
System.out.println(jwtToken);
// 创建一个验证的对象,必须使用签名密钥字符串
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjcsInVzZXJOYW1lIjoiYWRtaW4iLCJleHAiOjE2ODEyMDE3ODh9.Z8hTYjgRG1_Bd7iWav36xR1yXdmIokJLk81g2DW5tXY";
try {
DecodedJWT verify = jwtVerifier.verify(token);
System.out.println(verify.getClaim("userId").asInt());
System.out.println(verify.getClaim("userName").asString());
System.out.println("过期时间:" + verify.getExpiresAt());
} catch (TokenExpiredException e) {
//输出过期对象Instant
ZonedDateTime zonedDateTime = e.getExpiredOn().atZone(ZoneId.of("GMT+08:00"));
LocalDateTime time = zonedDateTime.toLocalDateTime();
System.out.println(time);
System.out.println(time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
System.out.println(e.getExpiredOn());
} catch (Exception e) {
System.out.println("未知错误");
}
}
}
```
```java
package cn.webrx;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@SpringBootApplication
@Slf4j
public class App implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
//log.info("hello world "+ SpringBootVersion.getVersion());
//-------------------------生成令牌
//令牌有效期 10分钟
Date date = new Date(System.currentTimeMillis()+1000*60*10);
//签名
String secret = "webrx";
JWTCreator.Builder builder = JWT.create();
Map header = new HashMap<>();
header.put("alg","HS256");
header.put("typ","JWT");
String t1 = builder.withHeader(header).withClaim("name","张三丰").withExpiresAt(date).sign(Algorithm.HMAC256(secret));
System.out.println(t1);
//
//-------------------------校验令牌
//String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoi5byg5LiJ5LiwIiwiZXhwIjoxNjk1NzEwNzc2fQ.12x9-83lQ6Du_NmEAmbaFTMADGT-HBafvii4IcfslKM";
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoi5byg5LiJ5LiwIiwiZXhwIjoxNjk1NzEwNzc2fQ.12x9-83lQ6Du_NmEAmbaFTMADGT-HBafvii4IcfslKM";
//检查
JWTVerifier jwtver = JWT.require(Algorithm.HMAC256(secret)).build();
try {
DecodedJWT dec = jwtver.verify(token);
System.out.printf("%tF %()) // Header 格式规范
//.withClaim("userId", 21) // Payload 数据
//.withClaim("userName", "admin")
// .withExpiresAt(calendar.getTime()) // 参数要求是java.util.Date 实例 ,过期时间
// .sign(Algorithm.HMAC256("webrx")); // 签名用的webrx
//System.out.println(token);
}
}
```
### 验证码实现
```xml
com.github.whvcse
easy-captcha
1.6.2
org.openjdk.nashorn
nashorn-core
15.4
```
生成验证码图片
```java
package cn.webrx.controller;
import cn.webrx.service.CaptchaService;
import com.wf.captcha.ArithmeticCaptcha;
import com.wf.captcha.ChineseGifCaptcha;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
@RestController
public class CaptchaController {
@Autowired
CaptchaService cs;
@GetMapping("/check")
public Map check() {
Map map = new HashMap<>();
map.put("code", "200");
map.put("msg", "验证码");
//验证码key
String checkkey = UUID.randomUUID().toString();
map.put("checkkey", checkkey);
Random rand = new Random();
int num = rand.nextInt(1,5);
//中文Gif动态验证码
Captcha captcha = switch (num) {
case 1 -> new ChineseGifCaptcha(130, 40);
case 2 -> new SpecCaptcha(130, 40);
case 3 -> new ArithmeticCaptcha(130, 40);
default -> new GifCaptcha(130, 40);
};
int len = rand.nextInt(2,6);
captcha.setLen(len);
//验证码
map.put("check", captcha.toBase64());
//保存验证码的值
String value = captcha.text();
System.out.println(value);
//checkkey captcha.text() redis缓存 mysql memory
cn.webrx.entity.Captcha cc = new cn.webrx.entity.Captcha();
cc.setId(checkkey);
cc.setValue(value);
cs.save(cc);
return map;
}
}
```
数据库
```sql
-- 建立临时表,用于存储会话验证码
create table t_captcha(
id char(36) primary key,
value varchar(10),
create_time timestamp default CURRENT_TIMESTAMP on UPDATE CURRENT_TIMESTAMP
)engine=memory;
-- 定义事件1分钟就会删除
create event capdel on schedule every 1 minute
do delete from t_captcha where create_time < adddate(now(),interval -1 minute);
```
vue
```js
登录
```

### 加密
基本的l加密方法md5 sha
```java
String p2(String str,String type) throws NoSuchAlgorithmException {
StringBuilder sbu = new StringBuilder();
MessageDigest md = MessageDigest.getInstance(type);
for(byte b : md.digest(str.getBytes())){
sbu.append(String.format("%02x",b));
}
return sbu.toString();
}
@Test
void p1() throws NoSuchAlgorithmException {
String s = "123";
String p1 = p2(s,"md5");
String p2 = p2(s,"sha");
System.out.println(s);
System.out.println(p1);
System.out.println(p2);
StringBuilder sbu = new StringBuilder();
sbu.append(p1.substring(0,5));
sbu.append(p2.substring(0,5));
sbu.append(p1.substring(10,20));
sbu.append(p2.substring(10,20));
sbu.append(p1.substring(p1.length()-1));
sbu.append(p2.substring(p2.length()-1));
System.out.println(sbu);
System.out.println(sbu.toString().length());
}
```
加盐,动态密文
```xml
org.springframework.security
spring-security-core
6.1.4
```
```java
@Test
void p4(){
//60位密文 System.out.println("$2a$10$SRZ8mKoF1yWpD0BkPKZzM.Dvc5Tgu.mFRoDm3ArotZ9RGuZkbLb/G".length());
System.out.println("$2a$10$QR4BJxq0z8XglOVCJvJguOvTKFxMixWFYeKcKIBXJpyyqqbiGoihq".length());
}
@Test
void p3() {
PasswordEncoder pe = new BCryptPasswordEncoder();
for (int i = 0; i < 5; i++) {
String encode = pe.encode("123"); //生成密文
System.out.println(encode);
}
//检查密码123 和密文是 System.out.println(pe.matches("123","$2a$10$CUAjmKHLSY6xwbxWbNaxN.9uICxr0IUxGzczbg08AFhpvT4dkv3jW"));
}
```
### api项目登录token
## 前端项目
### 建立vue3 项目
> 第一步:npm create vue app

> 第二步:添加项目依赖
```cmd
npm i element-plus axios @element-plus/icons-vue --save
npm install -D unplugin-vue-components unplugin-auto-import
```
> 第三步:配置项目开发环境
```text
.env
.env.development #开发
.env.production #生产环境
```
> 第四步:配置vite.config.js项目配置文件
```js
import {fileURLToPath, URL} from 'node:url'
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
//--------------------------------- server配置
, server: {
host: '0.0.0.0',
port: 80,
open: true,
proxy: { // 本地开发环境通过代理实现跨域,生产环境使用 nginx 转发
// 正则表达式写法 axios.defaults.baseURL = '/api'
'/api': {
target: 'http://localhost:8080', // 后端服务实际地址 http://localhost:8080/dbs url写成 /api/dbs
changeOrigin: true, //开启代理
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
//-----------------------------------
})
```
> 第五步:main.js
```js
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
```
### 配置项目
### 封装axios工具类
### 前端项目登录