Merge pull request 'master_dev' (#2) from xbx/Test-Warehouse:master_dev into xbx

Reviewed-on: http://hrbnu.club:3000/Big-Data-Lab/Test-Warehouse/pulls/2
This commit is contained in:
lq 2023-09-27 09:05:46 +08:00
commit e4be9007f1
62 changed files with 35461 additions and 0 deletions

10
HELP.md Normal file
View File

@ -0,0 +1,10 @@
# Getting Started
### Reference Documentation
For further reference, please consider the following sections:
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.7.16/maven-plugin/reference/html/)
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.7.16/maven-plugin/reference/html/#build-image)

81
pom.xml Normal file
View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.16</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>VueDemoV20</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>VueDemoV2.0</name>
<description>VueDemoV2.0</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jsonwebtoken 生成token的库 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package com.example.vuedemov20;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,29 @@
package com.example.vuedemov20;
public class Product {
private String state;
private String approver;
private String result;
//补全getset方法
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getApprover() {
return approver;
}
public void setApprover(String approver) {
this.approver = approver;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}

View File

@ -0,0 +1,35 @@
package com.example.vuedemov20.Token;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
//入口拦截设置哪些接口需要拦截或不拦截保护后端接口 防止未经授权的访问
@Configuration
public class IntercepterConfig implements WebMvcConfigurer {
private final TokenInterceptor tokenInterceptor;
// 构造方法
public IntercepterConfig(TokenInterceptor tokenInterceptor) {
this.tokenInterceptor = tokenInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//excludePathPatterns用来配置不需要拦截的路径
List<String> excludePath = new ArrayList<>();//List用来保存所有不需要拦截的路径
excludePath.add("/register"); //注册
excludePath.add("/login"); //登录
registry.addInterceptor(tokenInterceptor)//添加名为tokenInterceptor的拦截器
.addPathPatterns("/**") //指定拦截所有路径
.excludePathPatterns(excludePath);//排除不需要拦截的路径
WebMvcConfigurer.super.addInterceptors(registry);
}
}

View File

@ -0,0 +1,26 @@
package com.example.vuedemov20.Token;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class RedisUtil {
@Resource
private RedisTemplate<String, String> stringRedisTemplate;//这是一个使用redis的API可以直接用StringRedisTemplate
public void addTokens(String username, String token) {//存入token
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(username, token);
}
public String getTokens(String username) {//获取token
return stringRedisTemplate.opsForValue().get(username);
}
public void delTokens(String username) {//删除token在前端已经进行
stringRedisTemplate.delete(username);
}
}

View File

@ -0,0 +1,44 @@
package com.example.vuedemov20.Token;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
public class TokenGenerate {
private static final long EXPIRE_TIME= 15*60*1000;
private static final String TOKEN_SECRET="tokenqkj"; //密钥盐
public String generateToken(String username){
String token = null;
try{
Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
token = JWT.create()
.withIssuer("auth0")
.withClaim("username", username)
.withExpiresAt(expiresAt)
.sign(Algorithm.HMAC256(TOKEN_SECRET));
}catch (Exception e){
e.printStackTrace();
}
return token;
}
/**
* 签名验证
*/
public static boolean verify(String token){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT jwt = verifier.verify(token);
System.out.println("认证通过:");
System.out.println("issuer: " + jwt.getIssuer());
System.out.println("username: " + jwt.getClaim("username").asString());
System.out.println("过期时间: " + jwt.getExpiresAt());
return true;
} catch (Exception e){
System.out.println("没通过");
return false;
}
}
}

View File

@ -0,0 +1,42 @@
package com.example.vuedemov20.Token;
import com.example.vuedemov20.vueControll;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
//token拦截器,对拦截下的接口检查其的token是否符合只有
// 在提供一个有效的token时才能通过验证,否则给出认证失败的响应
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Resource
RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
//Axios 发起跨域请求前,浏览器也会首先发起 OPTIONS 预检请求检查服务器是否允许跨域访问
if(request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
System.out.println("允许跨域访问");
return true;
}
response.setCharacterEncoding("utf-8");
String token = redisUtil.getTokens(vueControll.Username);
if(token != null){
boolean result = TokenGenerate.verify(token);
if(result){
System.out.println("通过拦截器");
return true;
}
}
response.setCharacterEncoding("UTF-8");
PrintWriter out = null;
response.getWriter().write("认证失败,错误码:50000");
return false;//原为false
}
}

View File

@ -0,0 +1,102 @@
package com.example.vuedemov20;
import com.example.vuedemov20.Token.RedisUtil;
import com.example.vuedemov20.Token.TokenGenerate;
import mysql.*;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@RestController
@CrossOrigin //加上CrossOrigin可解决跨域问题
public class vueControll {
@Resource
RedisUtil redisUtil;
String token;
public static String Username;
@RequestMapping("/login")
public String tologin(@RequestParam("username") String username,@RequestParam("password") String password) throws SQLException {
ResultSet resultRegister = CheckRegister.MyAccount(username);
Username = username;
if(resultRegister.next()) {
if(username.equals(resultRegister.getString("username"))&&password.equals(resultRegister.getString("password"))) {
token = new TokenGenerate().generateToken(username);
redisUtil.addTokens(username,token);
return token;
}
}
return "false";
}
@RequestMapping("/register")
public String toRegister(@RequestParam("username") String username,@RequestParam("password") String password) throws SQLException {
ResultSet resultRegister = CheckRegister.MyAccount(username);
//还没有注册过
if(resultRegister.next()){
resultRegister.getString("username").equals(username);
return "false";
}
AddRegister.add(username, password);
return "true";
}
@PostMapping("/product")
public ResponseEntity<List<Product>> getProduct(@RequestBody Product product) throws SQLException {
//提取数据到List
ResultSet resultProduct = CheckProduct.MyAccount();
// 封装结果集到Product列表
List<Product> productList = new ArrayList<>();
while (resultProduct.next()) {
Product p = new Product();
p.setState(resultProduct.getString("state"));
p.setApprover(resultProduct.getString("approver"));
p.setResult(resultProduct.getString("result"));
productList.add(p);
}
return ResponseEntity.ok(productList);
}
@PostMapping("/addProduct")
public ResponseEntity<List<Product>> addProduct(@RequestBody Product product) throws SQLException {
//存入数据库
AddProduct.add(product.getState(),product.getApprover(),product.getResult());
//进行整体数据传输
ResultSet resultProduct = CheckProduct.MyAccount();
// 封装结果集到Product列表
List<Product> productList = new ArrayList<>();
while (resultProduct.next()) {
Product p = new Product();
p.setState(resultProduct.getString("state"));
p.setApprover(resultProduct.getString("approver"));
p.setResult(resultProduct.getString("result"));
productList.add(p);
}
return ResponseEntity.ok(productList);
}
@PostMapping("/deleteProduct")
public ResponseEntity<List<Product>> deleteProduct(@RequestBody Product product) throws Exception {
DeleteProduct.delete(product.getState(), product.getApprover(), product.getResult());
//进行整体数据传输
ResultSet resultProduct = CheckProduct.MyAccount();
// 封装结果集到Product列表
List<Product> productList = new ArrayList<>();
while (resultProduct.next()) {
Product p = new Product();
p.setState(resultProduct.getString("state"));
p.setApprover(resultProduct.getString("approver"));
p.setResult(resultProduct.getString("result"));
productList.add(p);
}
return ResponseEntity.ok(productList);
}
}

View File

@ -0,0 +1,19 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class AddProduct {
public static void add(String state,String approver,String result) throws SQLException {
String sql ="INSERT INTO product(state,approver,result) VALUES (?,?,?) ";
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1,state);
preparedStatement.setString(2,approver);
preparedStatement.setString(3,result);
preparedStatement.executeLargeUpdate();//插入数据
preparedStatement.close();
}
}

View File

@ -0,0 +1,18 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class AddRegister {
public static void add(String username,String password) throws SQLException {
String sql ="INSERT INTO register(username,password) VALUES (?,?) ";
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
preparedStatement.executeLargeUpdate();//插入数据
preparedStatement.close();
}
}

View File

@ -0,0 +1,16 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class CheckProduct {
public static ResultSet MyAccount() throws SQLException {
String sql = "SELECT* FROM product";
ResultSet resultSet;
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
resultSet = preparedStatement.executeQuery();//查询数据
return resultSet;
}
}

View File

@ -0,0 +1,17 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class CheckRegister {
public static ResultSet MyAccount(String username) throws SQLException {
String sql = "SELECT* FROM register where username = ?";
ResultSet resultSet;
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1, username);
resultSet = preparedStatement.executeQuery();//查询数据
return resultSet;
}
}

View File

@ -0,0 +1,20 @@
package mysql;
import java.sql.PreparedStatement;
public class DeleteProduct {
public static void delete(String state,String approver,String result ) throws Exception{
String sql = "delete from product where state=? AND approver = ? AND result = ?";
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1, state);
preparedStatement.setString(2, approver);
preparedStatement.setString(3, result);
preparedStatement.executeUpdate();//插入数据
preparedStatement.close();
}
}

View File

@ -0,0 +1,29 @@
package mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBC {
// static {
// try {
// Class.forName("com.mysql.cj.jdbc.Driver");
// } catch (ClassNotFoundException e) {
// throw new RuntimeException(e);
// }
// }
private static String url="jdbc:mysql://127.0.0.1:3306/vue";
private static String username="root";
private static String password="123456";
public static Connection getConnection() {
Connection connection;
try {
connection= DriverManager.getConnection(url,username,password);
return connection;
} catch (SQLException e) {
System.out.println("数据库未连接");
return null;
}
}
}

View File

@ -0,0 +1,13 @@
package mysql;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RegisterConfig {
private String username;
private String password;
}

View File

@ -0,0 +1,10 @@
server.port=8081
spring.datasource.url="jdbc:mysql://127.0.0.1:3306/vue"
spring.datasource.username="root"
spring.datasource.password="123456"
db.url=jdbc:mysql://127.0.0.1:3306/vue
db.user=root
db.password=123456
db.driver=com.mysql.jdbc.Driver

View File

@ -0,0 +1,31 @@
<?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为映射的根节点用来管理DAO接口
namespace指定DAO接口的完整类名表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口而这个实现类是一个Mapper对象
-->
<mapper namespace="lrs.user">
<!--
id = "接口中的方法名"
#{} :表示占位符,等价于 这是mybatis框架的语法
parameterType = "接口中传入方法的参数类型"
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
-->
<!-- 查询 根据id查询用户信息
select标签用于查询的标签
id:标签的唯一标识
resultType:定义返回的类型 把sql查询的结果封装到哪个实体类中
#{} :表示占位符,等价于 这是mybatis框架的语法
-->
<!-- 例子 -->
<select id="findById" resultType="User">
select * from register where username= #{username}
</select>
<insert id="add" parameterType="User">
insert into register values(#{username},#{password})
</insert>
</mapper>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.example.mybatistest"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/vue"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--注册mapper配置文件mapper文件路径配置
url:网络上的映射文件
注意映射配置文件位置要和映射器位置一样映射器在com.mycode.dao里
那么配置文件就应该在resources的com/mycode/dao目录下否则会报
Could not find resource com.mycode.dao.UserMapper.xml类似错误
-->
<mappers>
<!--下面编写mapper映射文件↓↓↓↓↓ 参考格式:<mapper resource="dao/UserMapper.xml"/> -->
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>

View File

@ -0,0 +1,13 @@
package com.example.vuedemov20;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

View File

@ -0,0 +1,17 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
parserOptions: {
parser: '@babel/eslint-parser'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}

23
前后端代码/前端/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1 @@
shamefully-hoist=true

View File

@ -0,0 +1,24 @@
# vue-demo
## Project setup
```
pnpm install
```
### Compiles and hot-reloads for development
```
pnpm run serve
```
### Compiles and minifies for production
```
pnpm run build
```
### Lints and fixes files
```
pnpm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

20263
前后端代码/前端/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
{
"name": "vue-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^1.5.0",
"core-js": "^3.8.3",
"jwt-decode": "^3.1.2",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -0,0 +1,8 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<style lang="scss">
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,5 @@
body, div, dl,dt,dd,ul,ol,li,h2,h3,h4,h5,h6,pre,form,fieldset,legend,input,textarea{
margin: 0;padding:0;}
body{text-align: center;}
a{ text-decoration: none;}
li{ list-style: none;}

View File

@ -0,0 +1,33 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import "./css/common.css"
Vue.prototype.$http = axios
Vue.config.productionTip = false
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
// 添加请求拦截器在请求头中加token
//使用 axios 的请求拦截器来实现在请求头中自动带上 token 的功能:
axios.interceptors.request.use(
config => {
if (localStorage.getItem('token')) {
config.headers.token = localStorage.getItem('token');
}
return config;
},
error => {
return Promise.reject(error);
});
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

View File

@ -0,0 +1,74 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "../views/Home.vue"
import Login from "../views/Login.vue"
import Product from "../views/Product.vue"
import BlogEdit from "../views/BlogEdit.vue"
import jwt_decode from "jwt-decode";
import store from "../store/index.js"
Vue.use(VueRouter)
const routes = [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/login",
name: "Login",
component: Login
},
{
path: "/product",
name: "Product",
component: Product
},
{
path: "/blogedit",
name: "BlogEdit",
component: BlogEdit
},
]
const router = new VueRouter({
mode:"history",
routes
})
//只有在跳转页面时才会执行
router.beforeEach((to, from, next) => {
//to 将要访问的路径
//from 代表从哪个路径而来
//next() 代表放行 next('xxx') 强制放行的xxx的路径
if(to.path==='/login'){
next();
}else{
const tokenStr = window.localStorage.getItem('token');
console.log(tokenStr);
if(!tokenStr){
alert("请你先登陆")
return next('/login')
}
const token = jwt_decode(tokenStr);
const currentTime = Date.now() / 1000;
if (currentTime > token.exp) {
store.commit("delToken"); //删除token
console.log("已超时");
alert("登陆过期,请你重新登陆")
return next('/login')
}
next();
}
})
export default router

View File

@ -0,0 +1,25 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
//定义一个state存储token信息
token: localStorage.getItem('token') ? localStorage.getItem('token') : ''
},
mutations: {
//登录后通过setToken存入token token保存在state和localStorage中,放入请求头中
setToken (state,token) {
state.token =token;
localStorage.setItem("token",token.token); //存储token
},
//登出后通过delToken清除token
delToken (state) {
state.token = '';
localStorage.removeItem("token"); //删除token
}
}
});
export default store;

View File

@ -0,0 +1,41 @@
<template>
<div class="m_content">
<h3>欢迎来到xbx的博客</h3>
<div class="maction">
<span><el-link type="primary" href="/#">主页</el-link></span>
<el-divider direction="vertical"></el-divider>
<span><el-link type="success" href="/#">发表博客</el-link></span>
</div>
<div class="block">
<div class="label">标题</div>
<el-input placeholder="请输入内容" clearable >
</el-input>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style>
.m_content {
max-width: 960px;
margin: 0 auto;
text-align: center;
}
.maction {
margin: 10px 0px;
}
/* 使标题和对话框同行 */
.block {
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,52 @@
<template>
<div class="m_content">
<h3>欢迎来到xbx的博客</h3>
<div class="maction">
<span><el-link type="primary" href="/#">主页</el-link></span>
<el-divider direction="vertical"></el-divider>
<span><el-link type="success" href="/#">发表博客</el-link></span>
</div>
<div class="block">
<el-timeline>
<el-timeline-item timestamp="2018/4/12" placement="top">
<el-card>
<h4>更新 Github 模板</h4>
<p>王小虎 提交于 2018/4/12 20:46</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2018/4/3" placement="top">
<el-card>
<h4>更新 Github 模板</h4>
<p>王小虎 提交于 2018/4/3 20:46</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2018/4/2" placement="top">
<el-card>
<a href="#">更新 Github 模板</a>
<p>王小虎 提交于 2018/4/2 20:46</p>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</div>
</template>
<script>
export default {
name: "HomePage"
}
</script>
<style>
.m_content {
max-width: 960px;
margin: 0 auto;
text-align: center;
}
.maction {
margin: 10px 0px;
}
</style>

View File

@ -0,0 +1,171 @@
<template>
<div class="login">
<el-card class="box-card">
<div class="clearfix">
<span>大数据专业实验室</span>
</div>
<div>
<el-tabs stretch>
<el-tab-pane label="登陆">
<el-form :model="loginForm" status-icon :rules="rules" label-width="80px" ref="loginForm">
<el-form-item label="用户名" prop="username">
<el-input type="text" v-model="loginForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="loginForm.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitLoginForm()">登陆</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="注册">
<el-form :model="registerForm" status-icon :rules="rules" label-width="80px" ref="loginForm">
<el-form-item label="用户名" prop="username">
<el-input type="text" v-model="registerForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="registerForm.password"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="configurePassword">
<el-input type="password" v-model="registerForm.configurePassword"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitRegisterForm()">注册</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
</el-card>
</div>
</template>
<script>
import axios from 'axios';
import { mapMutations } from 'vuex';//vuex
export default {
data() {
var validateUsername = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入用户名"));
} else if (value.length < 4) {
callback(new Error("长度不够"));
} else {
callback();
}
};
var validatePassword = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入密码"));
} else {
callback();
}
};
var validateConfigurePassword = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入密码")); //callback
} else if (value !== this.registerForm.password) {
callback(new Error("两次密码不一致"));
} else {
callback();
}
}
return {
loginForm: {
username: "",
password: "",
},
registerForm: {
username: "",
password: "",
configurePassword: ""
},
rules: {
username: [
{
validator: validateUsername,
trigger: "blur",
},
],
password: [
{
validator: validatePassword,
trigger: "blur",
},
],
configurePasswnpmord: [
{
validator: validateConfigurePassword,
trigger: "blur",
}
]
},
};
},
methods: {
//mapMutations Vuex mutations
// - Vuex mutations
...mapMutations(['setToken']),
submitLoginForm() {
let self = this //thisthis, Vue
var url = "http://localhost:8081/login?username=" + this.loginForm.username + "&password=" + this.loginForm.password
axios.get(url).then(function (response) { //, this Vue
var jsonObject = response.data;
var jsonString = JSON.stringify(jsonObject)
if (jsonString !== "false") {
window.localStorage.setItem("token", jsonString);
self.setToken({ token: jsonString });
self.$router.push('/product')
} else {
alert("账号或密码错误!")
}
})
},
submitRegisterForm() {
var url = "http://127.0.0.1:8081/register?username=" + this.registerForm.username + "&password=" + this.registerForm.password
axios.get(url).then(function (response) {
var jsonObject = response.data;
var jsonString = JSON.stringify(jsonObject)
if (jsonString === "true") {
alert("注册成功!")
} else {
alert("该用户已注册!")
}
})
},
},
name: "LoginPage",
};
</script>
<style>
.login {
width: 1200px;
margin: 0 auto;
}
.box-card {
width: 500px;
margin: 100px auto;
}
</style>

View File

@ -0,0 +1,196 @@
<template>
<div class="">
<div class="inline">
<p>审批状态</p>
<el-select v-model="value" clearable placeholder="请选择">
<el-option v-for="item in stateOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
<!-- 中间来个空格隔开 -->
<div style="width: 20px"></div>
<p>采购类别</p>
<el-select v-model="categoryValue" clearable placeholder="请选择">
<el-option v-for="item in categoryOptions" :key="item.categoryValue" :label="item.label"
:value="item.categoryValue"></el-option>
</el-select>
<div style="width: 20px"></div>
<el-button type="primary">查询</el-button>
<div style="width: 20px"></div>
<el-button type="primary" @click="createWord()">生成表格</el-button>
</div>
<!-- 设置按钮在最左边 type属性会改变按钮的样式,表示不同的意义-->
<div class="left">
<el-button type="primary" @click="increase()">新增</el-button>
<el-dialog title="新增" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="审批状态">
<el-input v-model="form.state" autocomplete="off" clearable></el-input>
</el-form-item>
<el-form-item label="审批人">
<el-input v-model="form.approver" autocomplete="off" clearable></el-input>
</el-form-item>
<el-form-item label="审核结果">
<el-input v-model="form.result" autocomplete="off" clearable></el-input>
</el-form-item>
</el-form>
<div>
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="sureIncrease()"> </el-button>
</div>
</el-dialog>
</div>
<br>
<!-- 缩小表格以适应屏幕 -->
<div style="width: 100%; overflow-x: auto" class="table">
<el-table :data="tableData" style="width: 100%" border>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="state" label="审批状态" width="100"></el-table-column>
<el-table-column prop="approver" label="审批人" width="100"></el-table-column>
<el-table-column prop="result" label="审核结果" width="100"></el-table-column>
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="primary" size=20px>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: {
data: {
type: [Array, String]
}
},
created() {
const formData = {
state: this.form.state,
approver: this.form.approver,
result: this.form.result,
};
axios.post('http://127.0.0.1:8081/product', formData).then((response) => {
this.tableData = response.data;
});
},
methods: {
handleClick(row) {
axios.post("http://127.0.0.1:8081/deleteProduct", row).then((res) => {
const productList = res.data;
this.tableData = productList;
this.$message.success('删除产品成功');
console.log(res.data);
});
},
//
increase() {
this.dialogFormVisible = true;
},
sureIncrease() {
const formData = {
state: this.form.state,
approver: this.form.approver,
result: this.form.result,
};
var url = "http://127.0.0.1:8081/addProduct"
axios.post(url, formData).then((res) => {
const productList = res.data;
this.tableData = productList;
this.$message.success('新增产品成功');
console.log(res.data);
});
this.dialogFormVisible = false;
},
createWord(){
// var url = "http://localhost:8081/createWord"
// axios.post(url, this.tableData).then((res) => {
// this.$message.success('');
// console.log(res.data);
// });
this.$message.success('功能已下线');
}
},
data() {
return {
stateOptions: [
{
value: "选项1",
label: "待审批",
},
{
value: "选项2",
label: "已通过",
},
{
value: "选项3",
label: "未通过",
},
],
value: "",
categoryOptions: [
{
categoryValue: "选项1",
label: "办公用具",
},
{
categoryValue: "选项2",
label: "生产材料",
},
{
categoryValue: "选项3",
label: "部门活动",
},
],
categoryValue: "",
tableData: [],
dialogFormVisible: false,
form: {
state: "",
approver: "",
result: "",
},
};
},
name: "ProductPage",
};
</script>
<style>
/* 使整个项目居中显示 */
.parent {
display: flex;
justify-content: center;
align-items: center;
justify-content: center;
}
.inline {
display: flex;
align-items: center;
justify-content: center;
}
/* 将left类中的按钮设置在审批状态下方 */
.left {
display: flex;
align-items: center;
justify-content: flex-start;
margin-left: 350px;
}
.table {
margin-left: 350px;
}
</style>

View File

@ -0,0 +1,4 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
package com.example.vuedemov20;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,29 @@
package com.example.vuedemov20;
public class Product {
private String state;
private String approver;
private String result;
//补全getset方法
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getApprover() {
return approver;
}
public void setApprover(String approver) {
this.approver = approver;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}

View File

@ -0,0 +1,35 @@
package com.example.vuedemov20.Token;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
//入口拦截设置哪些接口需要拦截或不拦截保护后端接口 防止未经授权的访问
@Configuration
public class IntercepterConfig implements WebMvcConfigurer {
private final TokenInterceptor tokenInterceptor;
// 构造方法
public IntercepterConfig(TokenInterceptor tokenInterceptor) {
this.tokenInterceptor = tokenInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//excludePathPatterns用来配置不需要拦截的路径
List<String> excludePath = new ArrayList<>();//List用来保存所有不需要拦截的路径
excludePath.add("/register"); //注册
excludePath.add("/login"); //登录
registry.addInterceptor(tokenInterceptor)//添加名为tokenInterceptor的拦截器
.addPathPatterns("/**") //指定拦截所有路径
.excludePathPatterns(excludePath);//排除不需要拦截的路径
WebMvcConfigurer.super.addInterceptors(registry);
}
}

View File

@ -0,0 +1,26 @@
package com.example.vuedemov20.Token;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class RedisUtil {
@Resource
private RedisTemplate<String, String> stringRedisTemplate;//这是一个使用redis的API可以直接用StringRedisTemplate
public void addTokens(String username, String token) {//存入token
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(username, token);
}
public String getTokens(String username) {//获取token
return stringRedisTemplate.opsForValue().get(username);
}
public void delTokens(String username) {//删除token在前端已经进行
stringRedisTemplate.delete(username);
}
}

View File

@ -0,0 +1,44 @@
package com.example.vuedemov20.Token;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
public class TokenGenerate {
private static final long EXPIRE_TIME= 15*60*1000;
private static final String TOKEN_SECRET="tokenqkj"; //密钥盐
public String generateToken(String username){
String token = null;
try{
Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
token = JWT.create()
.withIssuer("auth0")
.withClaim("username", username)
.withExpiresAt(expiresAt)
.sign(Algorithm.HMAC256(TOKEN_SECRET));
}catch (Exception e){
e.printStackTrace();
}
return token;
}
/**
* 签名验证
*/
public static boolean verify(String token){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT jwt = verifier.verify(token);
System.out.println("认证通过:");
System.out.println("issuer: " + jwt.getIssuer());
System.out.println("username: " + jwt.getClaim("username").asString());
System.out.println("过期时间: " + jwt.getExpiresAt());
return true;
} catch (Exception e){
System.out.println("没通过");
return false;
}
}
}

View File

@ -0,0 +1,42 @@
package com.example.vuedemov20.Token;
import com.example.vuedemov20.vueControll;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
//token拦截器,对拦截下的接口检查其的token是否符合只有
// 在提供一个有效的token时才能通过验证,否则给出认证失败的响应
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Resource
RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
//Axios 发起跨域请求前,浏览器也会首先发起 OPTIONS 预检请求检查服务器是否允许跨域访问
if(request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
System.out.println("允许跨域访问");
return true;
}
response.setCharacterEncoding("utf-8");
String token = redisUtil.getTokens(vueControll.Username);
if(token != null){
boolean result = TokenGenerate.verify(token);
if(result){
System.out.println("通过拦截器");
return true;
}
}
response.setCharacterEncoding("UTF-8");
PrintWriter out = null;
response.getWriter().write("认证失败,错误码:50000");
return false;//原为false
}
}

View File

@ -0,0 +1,102 @@
package com.example.vuedemov20;
import com.example.vuedemov20.Token.RedisUtil;
import com.example.vuedemov20.Token.TokenGenerate;
import mysql.*;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@RestController
@CrossOrigin //加上CrossOrigin可解决跨域问题
public class vueControll {
@Resource
RedisUtil redisUtil;
String token;
public static String Username;
@RequestMapping("/login")
public String tologin(@RequestParam("username") String username,@RequestParam("password") String password) throws SQLException {
ResultSet resultRegister = CheckRegister.MyAccount(username);
Username = username;
if(resultRegister.next()) {
if(username.equals(resultRegister.getString("username"))&&password.equals(resultRegister.getString("password"))) {
token = new TokenGenerate().generateToken(username);
redisUtil.addTokens(username,token);
return token;
}
}
return "false";
}
@RequestMapping("/register")
public String toRegister(@RequestParam("username") String username,@RequestParam("password") String password) throws SQLException {
ResultSet resultRegister = CheckRegister.MyAccount(username);
//还没有注册过
if(resultRegister.next()){
resultRegister.getString("username").equals(username);
return "false";
}
AddRegister.add(username, password);
return "true";
}
@PostMapping("/product")
public ResponseEntity<List<Product>> getProduct(@RequestBody Product product) throws SQLException {
//提取数据到List
ResultSet resultProduct = CheckProduct.MyAccount();
// 封装结果集到Product列表
List<Product> productList = new ArrayList<>();
while (resultProduct.next()) {
Product p = new Product();
p.setState(resultProduct.getString("state"));
p.setApprover(resultProduct.getString("approver"));
p.setResult(resultProduct.getString("result"));
productList.add(p);
}
return ResponseEntity.ok(productList);
}
@PostMapping("/addProduct")
public ResponseEntity<List<Product>> addProduct(@RequestBody Product product) throws SQLException {
//存入数据库
AddProduct.add(product.getState(),product.getApprover(),product.getResult());
//进行整体数据传输
ResultSet resultProduct = CheckProduct.MyAccount();
// 封装结果集到Product列表
List<Product> productList = new ArrayList<>();
while (resultProduct.next()) {
Product p = new Product();
p.setState(resultProduct.getString("state"));
p.setApprover(resultProduct.getString("approver"));
p.setResult(resultProduct.getString("result"));
productList.add(p);
}
return ResponseEntity.ok(productList);
}
@PostMapping("/deleteProduct")
public ResponseEntity<List<Product>> deleteProduct(@RequestBody Product product) throws Exception {
DeleteProduct.delete(product.getState(), product.getApprover(), product.getResult());
//进行整体数据传输
ResultSet resultProduct = CheckProduct.MyAccount();
// 封装结果集到Product列表
List<Product> productList = new ArrayList<>();
while (resultProduct.next()) {
Product p = new Product();
p.setState(resultProduct.getString("state"));
p.setApprover(resultProduct.getString("approver"));
p.setResult(resultProduct.getString("result"));
productList.add(p);
}
return ResponseEntity.ok(productList);
}
}

View File

@ -0,0 +1,19 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class AddProduct {
public static void add(String state,String approver,String result) throws SQLException {
String sql ="INSERT INTO product(state,approver,result) VALUES (?,?,?) ";
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1,state);
preparedStatement.setString(2,approver);
preparedStatement.setString(3,result);
preparedStatement.executeLargeUpdate();//插入数据
preparedStatement.close();
}
}

View File

@ -0,0 +1,18 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class AddRegister {
public static void add(String username,String password) throws SQLException {
String sql ="INSERT INTO register(username,password) VALUES (?,?) ";
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
preparedStatement.executeLargeUpdate();//插入数据
preparedStatement.close();
}
}

View File

@ -0,0 +1,16 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class CheckProduct {
public static ResultSet MyAccount() throws SQLException {
String sql = "SELECT* FROM product";
ResultSet resultSet;
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
resultSet = preparedStatement.executeQuery();//查询数据
return resultSet;
}
}

View File

@ -0,0 +1,17 @@
package mysql;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class CheckRegister {
public static ResultSet MyAccount(String username) throws SQLException {
String sql = "SELECT* FROM register where username = ?";
ResultSet resultSet;
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1, username);
resultSet = preparedStatement.executeQuery();//查询数据
return resultSet;
}
}

View File

@ -0,0 +1,20 @@
package mysql;
import java.sql.PreparedStatement;
public class DeleteProduct {
public static void delete(String state,String approver,String result ) throws Exception{
String sql = "delete from product where state=? AND approver = ? AND result = ?";
PreparedStatement preparedStatement;
preparedStatement = JDBC.getConnection().prepareStatement(sql);
preparedStatement.setString(1, state);
preparedStatement.setString(2, approver);
preparedStatement.setString(3, result);
preparedStatement.executeUpdate();//插入数据
preparedStatement.close();
}
}

View File

@ -0,0 +1,29 @@
package mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBC {
// static {
// try {
// Class.forName("com.mysql.cj.jdbc.Driver");
// } catch (ClassNotFoundException e) {
// throw new RuntimeException(e);
// }
// }
private static String url="jdbc:mysql://127.0.0.1:3306/vue";
private static String username="root";
private static String password="123456";
public static Connection getConnection() {
Connection connection;
try {
connection= DriverManager.getConnection(url,username,password);
return connection;
} catch (SQLException e) {
System.out.println("数据库未连接");
return null;
}
}
}

View File

@ -0,0 +1,13 @@
package mysql;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RegisterConfig {
private String username;
private String password;
}

View File

@ -0,0 +1,10 @@
server.port=8081
spring.datasource.url="jdbc:mysql://127.0.0.1:3306/vue"
spring.datasource.username="root"
spring.datasource.password="123456"
db.url=jdbc:mysql://127.0.0.1:3306/vue
db.user=root
db.password=123456
db.driver=com.mysql.jdbc.Driver

View File

@ -0,0 +1,31 @@
<?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为映射的根节点用来管理DAO接口
namespace指定DAO接口的完整类名表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口而这个实现类是一个Mapper对象
-->
<mapper namespace="lrs.user">
<!--
id = "接口中的方法名"
#{} :表示占位符,等价于 这是mybatis框架的语法
parameterType = "接口中传入方法的参数类型"
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
-->
<!-- 查询 根据id查询用户信息
select标签用于查询的标签
id:标签的唯一标识
resultType:定义返回的类型 把sql查询的结果封装到哪个实体类中
#{} :表示占位符,等价于 这是mybatis框架的语法
-->
<!-- 例子 -->
<select id="findById" resultType="User">
select * from register where username= #{username}
</select>
<insert id="add" parameterType="User">
insert into register values(#{username},#{password})
</insert>
</mapper>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.example.mybatistest"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/vue"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--注册mapper配置文件mapper文件路径配置
url:网络上的映射文件
注意映射配置文件位置要和映射器位置一样映射器在com.mycode.dao里
那么配置文件就应该在resources的com/mycode/dao目录下否则会报
Could not find resource com.mycode.dao.UserMapper.xml类似错误
-->
<mappers>
<!--下面编写mapper映射文件↓↓↓↓↓ 参考格式:<mapper resource="dao/UserMapper.xml"/> -->
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>

View File

@ -0,0 +1,13 @@
package com.example.vuedemov20;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Test
void contextLoads() {
}
}