SpringBoot项目实战(39)--Beetl网页HTML文件中静态图片及CSS、JS文件的引用和展示

news/2025/1/14 0:51:57/
htmledit_views">

        使用Beetl开发网页时,在网页中使用的CSS、JS、图片等静态资源需要进行适当的配置才可以展示。大致的过程如下:

    (1)首先Spring Security框架需要允许js、css、图片资源免授权访问。

    (2)网站开发时,如果网页文件不放在SpringBoot工程内部打包,单独指定了文件目录,需要在Config文件中加载文件系统中的网页目录。

     (3)网页文件中引用静态文件的路径不能使用相对路径,需要使用绝对路径。

     (4)如果使用了Nginx,静态资源文件路径还要加上 Nginx反向代理的路径。

下面是实现过程:

       首先贴一下之前openjweb-sys工程的WebSecurityConfig文件,增加了js目录、css目录、images目录的免授权访问:

package opackage org.openjweb.sys.config;import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.openjweb.core.service.CommUserService;
import org.openjweb.sys.auth.security.AESPasswordEncoder;
import org.openjweb.sys.auth.security.MD5PasswordEncoder;
import org.openjweb.sys.auth.security.MyAccessDecisionManager;
import org.openjweb.sys.auth.security.MyFilterInvocationSecurityMetadataSource;
import org.openjweb.sys.entry.JwtAuthenticationEntryPoint;
import org.openjweb.sys.filter.JwtAuthenticationFilter;
import org.openjweb.sys.handler.JWTLogoutSuccessHandler;
import org.openjweb.sys.handler.JwtAccessDeniedHandler;
import org.openjweb.sys.handler.LoginFailureHandler;
import org.openjweb.sys.handler.LoginSuccessHandler;
import org.openjweb.sys.provider.MyAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;@Slf4j
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredCommUserService userDetailService;@Beanpublic PasswordEncoder passwordEncoder(){return new AESPasswordEncoder();}@AutowiredLoginSuccessHandler loginSuccessHandler;@AutowiredLoginFailureHandler loginFailureHandler;@AutowiredJwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;@AutowiredJwtAccessDeniedHandler jwtAccessDeniedHandler;@AutowiredJWTLogoutSuccessHandler jwtLogoutSuccessHandler;@Value("${oauth2.server}")private boolean isOAuth2Server = false;private static final String[] ALLOW_URL_LIST = {//"/login","/logout","/captcha","/favicon.ico",//"/api/jwt/**","/api/cms/**","/api/b2c/**","/api/b2b2c/**","/api/sns/**","/api/comm/**","/api/cms1/**","/api/store/**","/demo/**","/oauth/**", //允许oauth认证的路径"/webjars/**", //webjars js允许的路径"/testduoyu","/i18n/**","/**/*.html", //swagger"/api/comm/user/login","/api/weixin/login","/api/weixin/getVueMenu","/api/comm/user/getUserInfo2","/front/**","/**/js/**","/**/images/**","/**/css/**"};//作用???暴露AuthenticationManager给其他Bean使用@Bean@Overrideprotected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();//return super.authenticationManagerBean();}//这个和上面的是什么区别?能一起用吗?/*@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception{return super.authenticationManagerBean();}*/@Overrideprotected void configure(HttpSecurity http) throws Exception {//下面注释掉的是第一阶段的示例/*  http.cors().and().csrf().disable()//登录表单.formLogin().and().authorizeRequests().antMatchers(ALLOW_URL_LIST).permitAll().anyRequest().authenticated();*///下面是第二阶段整合了数据库权限控制的示例log.info("是否配置了oauth2 server:::::");log.info(String.valueOf(this.isOAuth2Server));if(this.isOAuth2Server){log.info("OAUTH2模式...........");http.formLogin()//.loginPage("/login.html").loginProcessingUrl("/login").and().authorizeRequests().antMatchers("/login.html", "/img/**","/demo/**","/webjars/**",  "/testduoyu","/i18n/**","/api/b2c/b2carea/**","/api/store/**","/**/*.html", "/api/comm/user/login","/api/weixin/login","/api/weixin/getVueMenu","/api/comm/user/getUserInfo2", "/front/**","/**/js/**",  "/**/images/**",  "/**/css/**").permitAll().anyRequest().authenticated().and().csrf().disable();}else {log.info("非OAUTH2模式............");http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O object) {object.setSecurityMetadataSource(cfisms());object.setAccessDecisionManager(cadm());return object;}}).and().formLogin()//先注掉这个检查oauth认证//.successHandler(loginSuccessHandler) //登录成功处理.failureHandler(loginFailureHandler) //登录失败处理.loginProcessingUrl("/login").permitAll()//.loginProcessingUrl("/demo/jwt/login").permitAll().and().logout().logoutSuccessHandler(jwtLogoutSuccessHandler)// 禁用session.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)// 配置拦截规则.and().authorizeRequests().antMatchers(ALLOW_URL_LIST).permitAll().anyRequest().authenticated()// 异常处理器.and().exceptionHandling()//接口登录模式打开这个//.authenticationEntryPoint(jwtAuthenticationEntryPoint) //这个影响登录,会导致/login登录蔬菜.accessDeniedHandler(jwtAccessDeniedHandler)// 配置自定义的过滤器//这个jwtAuthenticationFilter 不加也执行了,是否增加了会调整多个过滤器的执行顺序.and().addFilter(jwtAuthenticationFilter()).logout().permitAll().and().csrf().disable();}}/*@BeanPasswordEncoder PasswordEncoder() {//return md5PasswordEncoder;//return aesPasswordEncoder;//这个不行return new AESPasswordEncoder();//return new BCryptPasswordEncoder();//return new Md5PasswordEncoder();}*//*@AutowiredMD5PasswordEncoder md5PasswordEncoder;@AutowiredAESPasswordEncoder aesPasswordEncoder;*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {if(true){//如果自定义AuthenticationProvider 则不使用这个//auth.userDetailsService(userDetailService).passwordEncoder(aesPasswordEncoder);//auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());DaoAuthenticationProvider provider = new DaoAuthenticationProvider();provider.setUserDetailsService(userDetailService);provider.setPasswordEncoder(passwordEncoder());auth.authenticationProvider(provider);}else{//自定义AuthenticationProviderauth.authenticationProvider(new MyAuthenticationProvider(userDetailService));}}@BeanMyAccessDecisionManager cadm() {//System.out.println("加载角色权限设置。。。。。。。。。。。。");return new MyAccessDecisionManager();}@BeanMyFilterInvocationSecurityMetadataSource cfisms() {//System.out.println("加载权限设置。。。。。。。。。。。。");return new MyFilterInvocationSecurityMetadataSource();}@Bean@ConditionalOnExpression("'${oauth2.server}'=='false'")JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());return jwtAuthenticationFilter;}
}

  然后在openjweb-core工程的WebMvcConfig中增加文件系统中静态资源目录:

     

package org.openjweb.core.config;import lombok.extern.slf4j.Slf4j;
import org.beetl.core.GroupTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;import java.util.HashMap;
import java.util.Map;@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {@Value("${beetl.fileTemplatesPath:}") String fileTemplatesPath;@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/testduoyu").setViewName("testduoyu");//不能命名testlocale 可能locale有冲突}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("fileTemplatePath::");log.info(fileTemplatesPath);if(!fileTemplatesPath.endsWith("/"))fileTemplatesPath+="/";//D:/tmp/beetl/templatesregistry.addResourceHandler("/**").addResourceLocations("file:"+fileTemplatesPath).addResourceLocations("classpath:/static/");}@Overridepublic void addInterceptors(InterceptorRegistry registry) {log.info("设置国际化参数lang...........");//默认拦截器 其中lang表示切换语言的参数名 LocaleChangeInterceptor 指定切换国际化语言的参数名。// 例如?lang=zh_CN 表示读取国际化文件messages_zh_CN.properties。//System.out.println("增加国际化拦截器...........");LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();localeInterceptor.setParamName("lang");// 指定设置国际化的参数registry.addInterceptor(localeInterceptor);}
}

在上面的代码中,增加了addResourceHandlers方法,此方法加载了文件系统fileTemplatePath目录的静态资源,在开发环境中,application-dev.yml中指定的fileTemplatePath是d:\tmp\beetl\templates。

项目的静态网页:

        假设项目的静态网页路径是D:\tmp\beetl\templates\cms\site\wenhua,在此路径下有js、css、images目录以及html文件,下面截取了局部的HTML文件:

html"><!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>中国文化网</title>
<meta name="keywords" content="中国文化网">
<meta name="description" content="中国文化网">
<link href="/clouds/cms/site/wenhua/css/common.css" rel="stylesheet" type="text/css" />
<link href="/clouds/cms/site/wenhua/css/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>
<link href="/clouds/cms/site/wenhua/css/index.css" rel="stylesheet" type="text/css" />
<link href="/clouds/cms/site/wenhua/css/focus1.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="/clouds/cms/site/wenhua/js/jquery.1.7.2.min.js"></script>
<script type="text/javascript" src="/clouds/cms/site/wenhua/js/koala.min.1.5.js"></script>
<script type="text/javascript">$(function(){ var pw = $('#po-pic').width();var sw = $(window).width();var lw = (pw - sw)/2;$('#po-pic').attr('style','margin-left:-'+lw+'px');})
</script>
</head>
<body>
<div class="top"><div class="layout"><div class="fl logo"><a href="#"><img src="/clouds/cms/site/wenhua/images/logo.jpg" width="257" height="70" border="0" /></a></div><div class="fr top-nav"><div class="fr search"><input type="text" name="search" class="fr" /><span>高级搜索&nbsp;&nbsp;<a href="#"><i class="fa fa-search fa-lg"></i></a></span></div><a href="#">邮箱登陆1</a><span>&emsp;|&emsp;</span></div><div class="clear"></div></div>
</div>

注意静态资源文件的引用:/clouds/cms/site/wenhua/css/common.css、/clouds/cms/site/wenhua/images/logo.jpg,其中clouds是使用Nginx反向代理将8001端口转发到了SpringBoot,如果没使用nginx,而是使用了localhost:8001,则不需要使用/clouds,后面/cms开头的路径则是针对模版文件跟路径下的相对路径,根路径为D:\tmp\beetl\templates。

     现在我们开发一个控制层类,用于展示静态页面。在openjweb-cms内容管理模块增加一个控制层类:

package org.openjweb.cms.controller;import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.openjweb.cms.service.CmsInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;import java.util.HashMap;
import java.util.Map;@Api(tags = "内容管理-前端查询")
@Slf4j
@Controller
@RequestMapping("/front") //public class CmsInfoController {@Autowiredprivate CmsInfoService cmsInfoService;@RequestMapping(value="/index")public String index( Model model) {return "cms/site/wenhua/index.html";//返回页面名}}

测试访问:http://localhost:8001/front/index (不使用nginx则html中静态资源不要加/clouds)

返回的静态页效果:


http://www.ppmy.cn/news/1562919.html

相关文章

【MySQL】count(*)、count(1)和count(列名)区别

问题&#xff1a;用count(*)&#xff0c;count(1)&#xff0c;count(列名)谁好呢? 其实&#xff0c;对于MyISAM引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。 Innodb引擎的表用count(*),count(1)直接读行数&#xff0c;复杂度是O(n)&#xff0c;因为innodb真的…

【算法】不基于比较的排序(图解)

目录 1.比较器 2.桶排序 2.1.计数排序 2.2.基数排序 3.排序算法的稳定性及其汇总 1.比较器 返回负数的时候&#xff0c;第一个参数排在前面 返回正数的时候&#xff0c;第二个参数排在前面 返回0的时候&#xff0c;谁在前面都无所谓 Override public static void comp…

Spring 中的常用注解

Spring 作为 Java 企业级开发中最广泛使用的框架之一&#xff0c;以其强大的功能和灵活性为开发者提供了高效的开发体验。在 Spring 中&#xff0c;注解&#xff08;Annotation&#xff09;是其核心机制之一&#xff0c;它简化了配置文件的繁琐操作&#xff0c;通过声明的方式实…

机器学习 - 如何理解函数集合中的准确性、召回率、F1分数呢?

在机器学习中&#xff0c;准确性&#xff08;Accuracy&#xff09;、召回率&#xff08;Recall&#xff09;、和F1分数是常用的模型性能评价指标&#xff0c;它们从不同的角度衡量模型的表现。要理解它们&#xff0c;首先需要了解它们的定义和适用场景&#xff1a; 1. 基本概念…

制造业该怎么做数据治理?

什么是数据治理&#xff1f; 简单来说&#xff0c;数据治理就是管好企业的数据家底&#xff0c;就像管家一样&#xff0c;得有规划、有监督、还得落实执行。目标就是让数据在整个生命周期里都保持高质量、合规合法、安全可靠、用起来方便。这可不光是收集、存储和使用数据那么…

用 Python 绘制可爱的招财猫

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​​​ ​​​​​​​​​ ​​​​ 招财猫&#xff0c;也被称为“幸运猫”&#xff0c;是一种象征财富和好运的吉祥物&#xff0c;经常…

【深度学习之PyTorch】

目录 一、什么是PyThon&#xff1f; 二、张量的创建 2.1 指定数据创建 2.2 指定形状、指定数据创建 2.3 创建指定类型的张量 2.4 创建线性张量 2.5 创建随机张量 2.6 创建全0张量 2.7 创建全1张量 2.8 创建指定张量 2.9 总结 三、张量的类型转换 3.1 张量元素的类型转…

加强移动应用安全,应用加固不可或缺

随着移动设备的普及&#xff0c;手机应用已经成为我们生活中不可或缺的一部分。无论是在线购物、银行支付&#xff0c;还是日常通讯、娱乐&#xff0c;移动应用都在处理中大量敏感数据&#xff0c;这使得它们成为网络攻击者的主要目标。针对这一不断加剧的安全威胁&#xff0c;…