当前位置:网站首页>Open source a set of minimalist front and rear end separation project scaffold
Open source a set of minimalist front and rear end separation project scaffold
2020-11-06 21:07:00 【itread01】
Preface
Fast Scaffold It's a very simple front and back separation project scaffold , Include a portal front end 、 One admin back-end , It can be used to quickly set up front and back end separation projects for secondary development
Technology stack
portal front end :vue + element-ui + avue, Use typescript Syntax encoding
admin back-end :springboot + mybatis-plus + mysql, Adopt jwt Authentication
Project structure
portal front end
Front end projects , It's us :Vue Project entry example , On this basis, I made a jump
introduce avue
avue, Based on element-ui Developed a front-end framework for many operations , We are, too test Test module Admin A simple test is done on the page
Official website :https://avuejs.com/
router To configure
router Routing configuration , newly added test Module menu routing ,beforeEach There is no token in the judgment , Jump to the login page
router.beforeEach(async(to, from, next) => {
console.log(" Jump start , The goal is :"+to.path);
document.title = `${to.meta.title}`;
// No token , Jump to the login page
if (to.name !== 'Login' && !TokenUtil.getToken()){
console.log(" No token , Jump to the login page ");
next({ name: 'Login' });
}
// Jump to page
next();
});
store To configure
store To configure , newly added user Properties ,getters Provide getUser Method , as well as mutations、actions Of setUser Method
import Vue from 'vue'
import Vuex from 'vuex'
import User from "@/vo/user";
import CommonUtil from "@/utils/commonUtil";
import {Object} from "@/utils/commonUtil"
import AxiosUtil from "@/utils/axiosUtil";
import TokenUtil from "@/utils/tokenUtil";
import SessionStorageUtil from "@/utils/sessionStorageUtil";
Vue.use(Vuex);
/*
Make an appointment , Components are not allowed to be changed directly store Example of state, It should be carried out action To distribute (dispatch) Event notification store To change
*/
export default new Vuex.Store({
state: {
user:User,
},
getters:{
getUser: state => {
return state.user;
}
},
mutations: {
SET_USER: (state, user) => {
state.user = user;
}
},
actions: {
async setUser({commit}){
let thid = this;
console.log(" call getUserByToken Interface get login user !");
AxiosUtil.post(CommonUtil.getAdminUrl()+"/getUserByToken",{token:TokenUtil.getToken()},function (result) {
let data = result.data as Object;
commit('SET_USER', new User(data.id,data.username));
// Set to sessionStorage
SessionStorageUtil.setItem("loginUser",thid.getters.getUser);
});
}
},
modules: {
}
})
Tool class encapsulation
axiosUtil.ts
Set global withCredentials,timeout
Set request Intercept , Set... In the request header token token
Set response Intercept , Set the unified response to the exception message prompt and jump to the login page when the token is invalid
It encapsulates post、get And so on , Convenient call
commonUtil.ts
It encapsulates the common use of 、 Common methods , For example, get the back-end service address 、 Get login users, etc
sessionStorageUtil.ts
Package sessionStorage Session level caching , Easy to set up cache
tokenUtil.ts
Package token Token utility class , Easy to set token Token to cookie
admin back-end
Back end projects , Using our :SpringBoot series ——MyBatis-Plus Integrated packaging , On this basis, adjustments have been made
Only keep tb_user Table module , Other tables and code modules don't need , Change the password to MD5 Encrypted storage
Configuration file
server:
port: 10086
spring:
application:
name: admin
datasource: # Database related
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mvc:
format:
date: yyyy-MM-dd HH:mm:ss
jackson:
date-format: yyyy-MM-dd HH:mm:ss #jackson Format the date arguments that respond back
time-zone: GMT+8
portal:
url: http://172.16.35.52:10010 # Front end address ( For cross domain configuration )
token:
secret: huanzi-qch #token Encrypt the private key ( Very important , Keep it secret )
expire:
time: 86400000 #token Effective time , Unit millisecond 24*60*60*1000
cors Security cross domain
establish MyConfiguration, Turn on cors Security cross domain , Details can be found in our previous blog :SpringBoot series ——CORS( Cross source resource sharing )
@Configuration
public class MyConfiguration {
@Value("${portal.url}")
private String portalUrl;
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(portalUrl)
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true).maxAge(3600);
}
};
}
}
jwt Authentication
maven introduce jwt Rely on
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>
JwtUtil Tool class , Package generation token, Check token, And according to token Get login users
/**
* JWT Tool class
*/
@Component
public class JwtUtil {
/**
* Expiration time , millisecond
*/
private static long TOKEN_EXPIRE_TIME;
@Value("${token.expire.time}")
public void setExpireTime(long expireTime) {
JwtUtil.TOKEN_EXPIRE_TIME = expireTime;
}
/**
* token Private key
*/
private static String TOKEN_SECRET;
@Value("${token.secret}")
public void setSecret(String secret) {
JwtUtil.TOKEN_SECRET = secret;
}
/**
* Generate signature
*/
public static String sign(String userId){
// Expiration time
Date date = new Date(System.currentTimeMillis() + TOKEN_EXPIRE_TIME);
// Private key and encryption algorithms
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// Set header information
HashMap<String, Object> header = new HashMap<>(2);
header.put("typ", "JWT");
header.put("alg", "HS256");
// With userID Generate signature
return JWT.create().withHeader(header).withClaim("userId",userId).withExpiresAt(date).sign(algorithm);
}
/**
* Verify signature
*/
public static boolean verity(String token){
// Token is empty
if(StringUtils.isEmpty(token)){
return false;
}
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
// Can I decrypt
DecodedJWT jwt = verifier.verify(token);
// Verification expiration time
if(new Date().after(jwt.getExpiresAt())){
return false;
}
return true;
} catch (IllegalArgumentException | JWTVerificationException e) {
ErrorUtil.errorInfoToString(e);
}
return false;
}
/**
* According to token Get users id
*/
public static String getUserIdByToken(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return jwt.getClaim("userId").asString();
} catch (IllegalArgumentException | JWTVerificationException e) {
ErrorUtil.errorInfoToString(e);
}
return null;
}
}
Login interceptor
LoginFilter Login interceptor , Do not block login requests 、 Cross domain pre check request , All other requests are intercepted to check whether there is a token
PS: We have configured global security across domains , But in the interceptor ,PrintWriter.print Go back response, To manually add a response header tag to allow the other party to cross domain
// Mark the current request Party to allow cross domain access
response.setHeader("Access-Control-Allow-Credentials","true");
response.setHeader("Access-Control-Allow-Headers","content-type, token");
response.setHeader("Access-Control-Allow-Methods","*");
response.setHeader("Access-Control-Allow-Origin",portalUrl);
/**
* Login interceptor
*/
@Component
public class LoginFilter implements Filter {
@Value("${server.servlet.context-path:}")
private String contextPath;
@Value("${portal.url}")
private String portalUrl;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String method = request.getMethod();
// Do not block login requests 、 Cross domain pre check request , All other requests are intercepted to check whether there is a token
if (!"/login".equals(request.getRequestURI().replaceFirst(contextPath,"")) && !"options".equals(method.toLowerCase())) {
String token = request.getHeader("token");
// Verify signature
if(!JwtUtil.verity(token)){
String dataString = "{\"status\":401,\"message\":\" Invalid token token , Access failed , Please log in again !\"}";
// eliminate cookie
Cookie cookie = new Cookie("PORTAL_TOKEN", null);
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
// Turn json A string is converted to Object thing , Set to Result And assign it to the return value , Remember to indicate that the current page can be accessed across domains
response.setHeader("Access-Control-Allow-Credentials","true");
response.setHeader("Access-Control-Allow-Headers","content-type, token");
response.setHeader("Access-Control-Allow-Methods","*");
response.setHeader("Access-Control-Allow-Origin",portalUrl);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = response.getWriter();
out.print(dataString);
out.flush();
out.close();
return;
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
Simple controller
IndexController controller , Provide three post Method :login Log in ,logout Log out ,getUserByToken Through token Token acquisition login user
@RestController
@RequestMapping("/")
@Slf4j
public class IndexController {
@Autowired
private TbUserService tbUserService;
/**
* Log in
*/
@PostMapping("login")
public Result<String> login(@RequestBody TbUserVo entityVo){
// Focus only on the user name 、 code
if(StringUtils.isEmpty(entityVo.getUsername()) || StringUtils.isEmpty(entityVo.getPassword())){
return Result.build(400," Account number or password cannot be empty ......","");
}
TbUserVo tbUserVo = new TbUserVo();
tbUserVo.setUsername(entityVo.getUsername());
// code MD5 After encryption, the ciphertext is stored , Match first MD5 Match after encryption
tbUserVo.setPassword(MD5Util.getMD5(entityVo.getPassword()));
Result<List<TbUserVo>> listResult = tbUserService.list(tbUserVo);
if(Result.OK.equals(listResult.getStatus()) && listResult.getData().size() > 0){
TbUserVo userVo = listResult.getData().get(0);
//token
String token = JwtUtil.sign(userVo.getId()+"");
return Result.build(Result.OK," Login successful !",token);
}
return Result.build(400," Account or password error ...","");
}
/**
* Log out
*/
@PostMapping("logout")
public Result<String> logout(HttpServletResponse response){
// eliminate cookie
Cookie cookie = new Cookie("PORTAL_TOKEN", null);
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
return Result.build(Result.OK," I drive this road , I planted this tree , To pass by from here on , leave token token !","");
}
/**
* Through token Token acquisition login user
*/
@PostMapping("getUserByToken")
public Result<TbUserVo> getUserByToken(@RequestBody TbUserVo entityVo){
String userId = JwtUtil.getUserIdByToken(entityVo.getToken());
Result<TbUserVo> result = tbUserService.get(userId);
result.getData().setPassword(null);
return userId == null ? Result.build(500," Operation failed !",new TbUserVo()) : result;
}
}
Effect demonstration
Log in
This is a minimalist login page 、 Login function , No token , The route will block the jump to the login page
Save after successful login token Token to cookie in , And get login user information , Store in Store in
To solve the problem of rearranging the page Store Data loss , At the same time, store a copy of the data to sessionStorage Get it , Reading Store When there is no information , Read cache first , If there is , Set it back to Store in
Leave blank after successful login Store、sessionStorage
Home
Minimalist project homepage , Path /, Usually used as a project home page , Now the page is a simple welcome page , It includes several router-link Routing and logout button
test Test
Integrated vue Simple tests such as data binding
info Test
Get the current active configuration environment Branch , Test the configuration of the file
admin Test
element-ui Match up avue, It can be built quickly admin Background management page and function
Packaged deployment
portal front end
It's already configured package.json Archives
"scripts": {
"dev": "vue-cli-service serve --mode dev",
"test": "vue-cli-service test --mode test",
"build": "vue-cli-service build --mode prod"
},
At the same time ,vue.config.js The build path is configured in
publicPath: './',
outputDir: 'dist',
assetsDir: 'static',
Execute build command , It will be in package.json Under the directory at the same level , establish dist Folder , The generated files are in it
Put the generated files in Tomcat In containers or other containers , Execution container , front end portal Project complete deployment
admin back-end
pom The file has already set the package configuration
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<finalName>${project.artifactId}</finalName>
<outputDirectory>package</outputDirectory>
</configuration>
</plugin>
maven Direct execution package command , It will be with pom File under the same level directory to create package Folder , Generated jar The bag is in it
Use java command :java -jar admin.jar, Execute jar package , back-end admin Project complete deployment
Postscript
A set of minimalist front and back separation project scaffolding is recorded here for the time being , I'll add it later
Open source code
notes :admin Back end database files are in admin Back end projects resources/sql Under the table of contents
The code is open source 、 Trust to my GitHub、 Code cloud :
GitHub:https://github.com/huanzi-qch/fast-scaffold
Code cloud :https://gitee.com/huanzi-qch/fast-scaffold
版权声明
本文为[itread01]所创,转载请带上原文链接,感谢
边栏推荐
- 检测证书过期脚本
- Tron smart wallet PHP development kit [zero TRX collection]
- How to understand Python iterators and generators?
- 2020-09-03:裸写算法:回形矩阵遍历。
- What are the criteria for selecting a cluster server?
- WeihanLi.Npoi 1.11.0/1.12.0 Release Notes
- An article will take you to understand SVG gradient knowledge
- es创建新的索引库并拷贝旧的索引库 实践亲测有效!
- Zero basis to build a web search engine of its own
- Filecoin has completed a major upgrade and achieved four major project progress!
猜你喜欢

An article will introduce you to HTML tables and their main attributes

Behind the record breaking Q2 revenue of Alibaba cloud, the cloud opening mode is reshaping

华为云微认证考试简介

Helping financial technology innovation and development, atfx is at the forefront of the industry

mongo 用户权限 登录指令

意派Epub360丨你想要的H5模板都在这里,电子书、大转盘、红包雨、问卷调查……

jenkins安装部署过程简记

What are the criteria for selecting a cluster server?

What are the common problems of DTU connection

如何对数据库账号权限进行精细化管理?
随机推荐
Axios learning notes (2): easy to understand the use of XHR and how to package simple Axios
Staying up late summarizes the key points of report automation, data visualization and mining, which is different from what you think
Even liver three all night, jvm77 high frequency interview questions detailed analysis, this?
How does cglib implement multiple agents?
Live broadcast preview | micro service architecture Learning Series live broadcast phase 3
What is the tensor in tensorflow?
An article taught you to use HTML5 SVG tags
nacos、ribbon和feign的簡明教程
What is the purchasing supplier system? Solution of purchasing supplier management platform
【:: 是什么语法?】
Look! Internet, e-commerce offline big data analysis best practice! (Internet disk link attached)
Markdown tricks
游戏开发中的新手引导与事件管理系统
Take you to learn the new methods in Es5
DC-1靶機
Diamond standard
Description of phpshe SMS plug-in
StickEngine-架构11-消息队列(MessageQueue)
list转换map(根据key来拆分list,相同key的value为一个list)
Asp.Net Core learning notes: Introduction