Spring Boot集成Thymeleaf实现无业务逻辑的页面跳转

Spring Boot集成Thymeleaf,默认情况下,前端的动态html页面放在resources/templates目录下,浏览器如果要访问这个目录下的页面,必须先发一个请求到Controller方法,由该方法返回一个页面的路径加名称前缀实现浏览器上展示动态页面

package com.zhutao.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/indexPage")
public class IndexController {
	
	@GetMapping
	public String toIndex() {
		return "index";
	}
}

如上,浏览器要访问resources/templates/index.html页面,必须先发请求http://ip:port/contextPath/indexPage。

如果templates下面有很多个动态页面,这么干是否觉得麻烦?能否通过http://ip:port/contextPath/index就能访问到templates/index.html界面?

Spring Boot提供了WebMvcConfigurer,该方法有个addViewControllers方法,可以实现这种想法

package com.zhutao.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class WebMvcConfigTemp implements WebMvcConfigurer {
	
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/index");
	}

}

这个效果类似下面的代码

package com.zhutao.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping
public class PageController {
	
	@GetMapping("/index")
	public String toIndex() {
		return "/index";
	}

}

但是如果有很多个页面,都通过registry注册,是否又显得很麻烦,能否更简单一点。

思路:在程序启动的时候,自动的读取templates目录下的html文件,通过registry注册,以下是实现,分两种情况考虑,第一本地开发环境运行时,可以通过文件系统读取所有的html文件;第二,通过运行jar包来启动程序,就不能再通过File读取所有的html文件,只能解析jar包来读取所有的html文件

package com.zhutao.demo.config;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
	
	private static Logger logger = LoggerFactory.getLogger(WebMvcConfig.class);
	//默认值为classpath:/templates/,和springboot保持一致
	@Value("${spring.thymeleaf.prefix:classpath:/templates/}")
	private String prefix;
	//默认值为.html,和springboot保持一致
	@Value("${spring.thymeleaf.prefix:.html}")
	private String suffix;
	
	@Resource
	private ResourceLoader resourceLoader;
	
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		String prefixName = prefix.substring("classpath:".length());
		if(prefixName.startsWith("/")) {
			prefixName = prefixName.substring(1);
		}
		if(prefixName.endsWith("/")) {
			prefixName = prefixName.substring(0,prefixName.length()-1);
		}
		org.springframework.core.io.Resource resource = resourceLoader.getResource(prefix);
		JarFile jarFile = null;
		try {
			String path = resource.getURL().getPath();
			//打成jar包后的场景
			if(path.indexOf(".jar!/BOOT-INF/classes!/"+prefixName+"/") != -1) {
				jarFile = new JarFile(path.substring("file:".length(),path.lastIndexOf("!/BOOT-INF/classes!")));
				Enumeration<JarEntry> jarEntries = jarFile.entries();
				while(jarEntries.hasMoreElements()) {
					JarEntry jarEntry = jarEntries.nextElement();
					String classPrefix = "BOOT-INF/classes/"+prefixName+"/";
					if(jarEntry.getName().startsWith(classPrefix) && jarEntry.getName().endsWith(suffix)) {
						String url = jarEntry.getName().substring(classPrefix.length()-1,jarEntry.getName().length() - suffix.length());
						registry.addViewController(url);
					}
				}
			} else {
				//本地开发环境的场景
				File prefixFile = resource.getFile();
				List<File> allHtmlFiles = htmlFiles(prefixFile);
				if(allHtmlFiles == null || allHtmlFiles.isEmpty()) {
					return;
				}
				int prefixFilePathLength = prefixFile.getPath().length();
				for(File e : allHtmlFiles) {
					String url = e.getPath().substring(prefixFilePathLength,e.getPath().length()-suffix.length());
					registry.addViewController(url);
				}
			}
		} catch (IOException e) {
			logger.error("自动将模板页面的路径映射为controller的url时异常",e);
		} finally {
			if(jarFile != null) {
				try {
					jarFile.close();
				} catch (IOException e) {
					logger.error("关闭jar文件时异常",e);
				}
			}
		}
	}
	
	private List<File> htmlFiles(File file) {
		File[] subFiles = file.listFiles();
		if(subFiles == null || subFiles.length == 0) {
			return new ArrayList<File>();
		}
		List<File> files = new ArrayList<>();
		for(File subFile : subFiles) {
			if(subFile.isFile()) {
				if(subFile.getName().toLowerCase().endsWith(suffix)) {
					files.add(subFile);
				}
			} else {
				List<File> fs = htmlFiles(subFile);
				if(fs != null && !fs.isEmpty()) {
					files.addAll(fs);
				}
			}
		}
		return files;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值