springboot+springsecurity+elementui博客系统-dsblog

欢迎关注博主公众号「java大师」, 回复【dsblog】获取源码

一、效果图展示

一、网站前台

1、首页

在这里插入图片描述

在这里插入图片描述

2、内容页

在这里插入图片描述

在这里插入图片描述

3、最新文章页面

在这里插入图片描述

二、网站后台

1、登录页

在这里插入图片描述

2、首页

在这里插入图片描述

3、栏目管理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、文章管理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、后端(swagger-ui)

在这里插入图片描述

二、 确定需求方案

后台进行栏目和文章的编辑,编辑完后前台展示。

三、整体架构设计

  1. 前端基于Vue+ElementUi,使用WebStorm编辑器;
  2. 后端基于Springboot+SpringSecurity+MyBatisPlus+JWT+Redis实现,使用 IDEA 编辑器;
  3. 数据传输格式:JSON;
  4. 数据库:mysql

三、编码实现 (关键代码)

1、前端Vue代码 – main.js

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import router from './router'
import store from './store'
import {initMenu} from  '/src/utils/menus'
import {getUserInfo} from  '/src/utils/http'
import 'font-awesome/css/font-awesome.css'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css';

Vue.config.productionTip = false

Vue.use(ElementUI);
Vue.use(mavonEditor)

router.beforeEach((to,from,next)=>{
	if(window.sessionStorage.getItem("token")){
		initMenu(router,store);
		console.log(router);
		if(!window.sessionStorage.getItem('user')){
			return getUserInfo().then(res=>{
				window.sessionStorage.setItem('user',JSON.stringify(res));
				next();
			})
		}
		next();
	}else{
		if(to.path=='/'){
			next();
		}else{
			next('/?redirect='+to.path);
		}
	}
})

new Vue({
	el: '#app',
	router,
	store,
	render: h => h(App),
}).$mount('#app')

2、前端JS代码 – 动态路由

import {
	getNav
} from './http.js'

export const initMenu = (router, store) => {
	if (store.state.routes.length > 0) {
		return;
	}

	getNav().then(data => {
		if (data) {
			let fmtRoutes = formatRoutes(data);
			//动态路由
			router.addRoutes(fmtRoutes);
			router.options.routes = fmtRoutes;
			//数据存入vuex
			store.commit('initRoutes',fmtRoutes);
		}
	})

}

export const dealPath=(path=>{
	return ((path.split('/')).length-1)>1?path.substring(path.indexOf("/"),path.lastIndexOf("/")):path.substring(path.indexOf("/"),path.length)
})


export const formatRoutes = (routes) => {
	let fmtRoutes = [];
	routes.forEach(router=>{
		let{
			path,
			component,
			name,
			iconCls,
			children
		} = router;
		if(children&&children instanceof Array){
			children = formatRoutes(children);
		}
		let fmtRouter = {
			path:path,
			name:name,
			iconCls:iconCls,
			children:children,
			component:()=>import(`../views${dealPath(path)}/${component}.vue`),
			// component:component
		}
		fmtRoutes.push(fmtRouter);
	})
	return fmtRoutes;
}

3、后端Java代码 SecurityConfig

package com.dsblog.server.config.security;

import com.dsblog.server.filter.CustomFilter;
import com.dsblog.server.filter.CustomUrlDecisionManager;
import com.dsblog.server.model.User;
import com.dsblog.server.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private IUserService userService;
    @Autowired
    private RestAuthorizationEntryPoint restAuthorizationEntryPoint;
    @Autowired
    private RestAccessDeniedHandler restAccessDeniedHandler;
    @Autowired
    private CustomFilter customFilter;
    @Autowired
    private CustomUrlDecisionManager customUrlDecisionManager;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/login",
                "/logout",
                "/css/**",
                "/js/**",
                "/index.html",
                "favicon.ico",
                "/doc.html",
                "/webjars/**",
                "/swagger-resources/**",
                "/v2/api-docs/**",
                "/captcha",
                "/ws/**",
                "/static/**",
                "/api/**"
        );
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setAccessDecisionManager(customUrlDecisionManager);
                        o.setSecurityMetadataSource(customFilter);
                        return o;
                    }
                })
                .and()
                .headers()
                .cacheControl();
        //添加Jwt登录授权拦截器
        http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加未登录和未授权结果返回
        http.exceptionHandling()
                .accessDeniedHandler(restAccessDeniedHandler)
                .authenticationEntryPoint(restAuthorizationEntryPoint);

    }

    @Override
    @Bean
    public UserDetailsService userDetailsService(){
        return username -> {
            User user = userService.getUserByUsername(username);
            if(null!=user){
                user.setRoles(userService.getRoles(user.getId()));
                return user;
            }
            throw new UsernameNotFoundException("用户名或密码不正确");
        };
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public  JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("//localhost:8080"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",configuration);
        return source;
    }
}

4、后端Java代码 swagger配置

package com.dsblog.server.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .pathMapping("/")
                .apiInfo(apiInfo())
                .select()
                //swagger要扫描的包路径
                .apis(RequestHandlerSelectors.basePackage("com.dsblog.server.controller"))
                .paths(PathSelectors.any())
                .build()
                .securityContexts(securityContexts())
                .securitySchemes(securitySchemes());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("dsblog接口文档")
                .contact(new Contact("java大师","//localhost:8081/doc.html","[email protected]"))
                .version("1.0").description("dsblog接口文档").build();
    }

    private List<SecurityContext> securityContexts() {
        //设置需要登录认证的路径
        List<SecurityContext> result = new ArrayList<>();
        result.add(getContextByPath("/.*"));
        return result;
    }

    private SecurityContext getContextByPath(String pathRegex) {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex(pathRegex))
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        List<SecurityReference> result = new ArrayList<>();
        AuthorizationScope authorizationScope = new AuthorizationScope("global",
                "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        result.add(new SecurityReference("Authorization", authorizationScopes));
        return result;
    }

    private List<ApiKey> securitySchemes() {
        //设置请求头信息
        List<ApiKey> result = new ArrayList<>();
        ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
        result.add(apiKey);
        return result;
    }

}

# 四、开发配置&代码结构说明

## 1、Java开发环境配置

![图片](//img-blog.csdnimg.cn/img_convert/facc4116644c055e4996689af09d3eea.png)

 ![图片](//img-blog.csdnimg.cn/img_convert/c186f6ad7dd5b837a632f609dd51efc7.png)



![图片](//img-blog.csdnimg.cn/img_convert/6964f07d402e8f04edf634108b4474b4.png)

 然后GENERATE,下载包即可。

## 2、代码结构说明 

### a、项目路径

![在这里插入图片描述](//img-blog.csdnimg.cn/442de78b283745568d81714f1b6b563d.png#pic_center)




### **b、application.yml配置**

![在这里插入图片描述](//img-blog.csdnimg.cn/c0beb7d293bc4b0e94f41d7dd93cd277.png#pic_center)
Tags: