Beetl模板创建自定义标签来仿造jsp 中<c:import>功能
现在在用beetl模板渲染画面,有时需要加载其他模板的内容,但是又不想使用beetl模板里的内嵌其他模板方式,想直接通过url请求的方式进行渲染,所以就扒一下c:import的源码改造成beetl的自定义标签,对于我这种扒代码的行为,我想说我站在了前辈的肩膀上,大家不要喷,哈哈
目的是要在btl模板文件中使用如下标签就可在画面渲染时将此url渲染的画面加载到当前画面中。
那么开始搞代码
首先在resouces目录下创建beetl.properties,在程序启动时,beetl模板会自动加载其中内容。
# 自定义配置
DELIMITER_STATEMENT_START=<%
DELIMITER_STATEMENT_END=%>
TAG.liyi.import=com.xxx.xxx.xxx.tag.beetl.BeetlImportTag
这里定义好Tag的名称以及扫描类的位置
然后在相应包下面创建对应的类BeetlImportTag,在这里我们直接继承beetl的GeneralVarTagBinding类。
继承此类是因为我们可以用getAttributeValue方法直接获取到url
然后就是核心了,使用什么方式可将发送内部url请求渲染画面,答案就是RequestDispatcher,使用dispatcher.include(request, response);方法即可实现请求,小伙伴们可以百度此方法详细了解下~
直接贴上具体代码
/**
* 自定义btl的import标签 (仿制c:import)
*
* @author li_yi_neu
*/
public class BeetlImportTag extends GeneralVarTagBinding {
public static final String VALID_SCHEME_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
public static final String DEFAULT_ENCODING = "ISO-8859-1";
private String url; // 'url' attribute
private boolean isAbsoluteUrl; // is our URL absolute?
private String varReader; // 'varReader' attribute
private String charEncoding; // 'charEncoding' attrib.
private ParamManager params; // parameters
private String urlWithParams; // URL with parameters, if applicable
private String context; // 'context' attribute
private ServletRequest request;
private ServletResponse response;
private void init() {
url = varReader = context = charEncoding = urlWithParams = null;
params = SpringBootUtil.getBean(ParamManager.class);
}
@Override
public void render() {
init();
url = (String) getAttributeValue("url");
if (request == null) {
request = BootServletUtils.getRequest();
}
if (response == null) {
response = BootServletUtils.getResponse();
}
if (url == null || url.equals("")) {
throw new BeetlTagException("error");
}
isAbsoluteUrl = isAbsoluteUrl();
try {
if (varReader == null) {
String str = acquireString();
ctx.byteWriter.writeString(str);
}
}
catch (IOException ex) {
throw new BeetlTagException(ex.toString(), ex);
}
}
private boolean isAbsoluteUrl() throws BeetlTagException {
return isAbsoluteUrl(url);
}
public static boolean isAbsoluteUrl(
String url) {
// a null URL is not absolute, by our definition
if (url == null)
return false;
// do a fast, simple check first
int colonPos;
if ((colonPos = url.indexOf(":")) == -1)
return false;
// if we DO have a colon, make sure that every character
// leading up to it is a valid scheme character
for (int i = 0; i < colonPos; i++)
if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1)
return false;
// if so, we've got an absolute url
return true;
}
private String acquireString() throws IOException, BeetlTagException {
if (isAbsoluteUrl) {
// for absolute URLs, delegate to our peer
BufferedReader r = new BufferedReader(acquireReader());
StringBuffer sb = new StringBuffer();
int i;
// under JIT, testing seems to show this simple loop is as fast
// as any of the alternatives
//
// gmurray71 : putting in try/catch/finally block to make sure the
// reader is closed to fix a bug with file descriptors being left open
try {
while ((i = r.read()) != -1)
sb.append((char) i);
}
catch (IOException iox) {
throw iox;
}
finally {
r.close();
}
return sb.toString();
}
else {
// handle relative URLs ourselves
// URL is relative, so we must be an HTTP request
if (!(request instanceof HttpServletRequest && response instanceof HttpServletResponse))
throw new BeetlTagException("error");
// retrieve an appropriate ServletContext
ServletContext c = null;
String targetUrl = targetUrl();
if (context != null)
c = request.getServletContext().getContext(context);
else {
c = request.getServletContext();
// normalize the URL if we have an HttpServletRequest
if (!targetUrl.startsWith("/")) {
String sp = ((HttpServletRequest) request).getServletPath();
targetUrl = sp.substring(0, sp.lastIndexOf('/')) + '/' + targetUrl;
}
}
if (c == null) {
throw new BeetlTagException();
}
// from this context, get a dispatcher
RequestDispatcher rd = c.getRequestDispatcher(stripSession(targetUrl));
if (rd == null)
throw new BeetlTagException();
// include the resource, using our custom wrapper
//ImportResponseWrapper irw = new ImportResponseWrapper();
// spec mandates specific error handling form include()
try {
rd.include(request, response);
//rd.include(request, irw);
}
catch (Exception ex) {
throw new BeetlTagException(ex);
}
// disallow inappropriate response codes per JSTL spec
// recover the response String from our wrapper
return "";
}
}
private Reader acquireReader() throws IOException, BeetlTagException {
if (!isAbsoluteUrl) {
// for relative URLs, delegate to our peer
return new StringReader(acquireString());
}
else {
// absolute URL
String target = targetUrl();
try {
// handle absolute URLs ourselves, using java.net.URL
URL u = new URL(target);
URLConnection uc = u.openConnection();
InputStream i = uc.getInputStream();
// okay, we've got a stream; encode it appropriately
Reader r = null;
String charSet;
if (charEncoding != null && !charEncoding.equals("")) {
charSet = charEncoding;
}
else {
// charSet extracted according to RFC 2045, section 5.1
String contentType = uc.getContentType();
if (contentType != null) {
charSet = getContentTypeAttribute(contentType, "charset");
if (charSet == null)
charSet = DEFAULT_ENCODING;
}
else {
charSet = DEFAULT_ENCODING;
}
}
try {
r = new InputStreamReader(i, charSet);
}
catch (Exception ex) {
r = new InputStreamReader(i, DEFAULT_ENCODING);
}
// check response code for HTTP URLs before returning, per spec,
// before returning
if (uc instanceof HttpURLConnection) {
int status = ((HttpURLConnection) uc).getResponseCode();
if (status < 200 || status > 299)
throw new BeetlTagException(status + " " + target);
}
return r;
}
catch (IOException ex) {
throw new BeetlTagException();
}
catch (RuntimeException ex) { // because the spec makes us
throw new BeetlTagException();
}
}
}
private String targetUrl() {
if (urlWithParams == null)
urlWithParams = params.aggregateParams(url);
return urlWithParams;
}
public static String stripSession(
String url) {
StringBuffer u = new StringBuffer(url);
int sessionStart;
while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) {
int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
if (sessionEnd == -1)
sessionEnd = u.toString().indexOf("?", sessionStart + 1);
if (sessionEnd == -1) // still
sessionEnd = u.length();
u.delete(sessionStart, sessionEnd);
}
return u.toString();
}
public static String getContentTypeAttribute(
String input,
String name) {
int begin;
int end;
int index = input.toUpperCase().indexOf(name.toUpperCase());
if (index == -1)
return null;
index = index + name.length(); // positioned after the attribute name
index = input.indexOf('=', index); // positioned at the '='
if (index == -1)
return null;
index += 1; // positioned after the '='
input = input.substring(index).trim();
if (input.charAt(0) == '"') {
// attribute value is a quoted string
begin = 1;
end = input.indexOf('"', begin);
if (end == -1)
return null;
}
else {
begin = 0;
end = input.indexOf(';');
if (end == -1)
end = input.indexOf(' ');
if (end == -1)
end = input.length();
}
return input.substring(begin, end).trim();
}
}
这里还需要另外两个辅助类ParamManager和SpringBootUtil
@Component
public class ParamManager {
//*********************************
// Private state
private List names = new LinkedList();
private List values = new LinkedList();
private boolean done = false;
//*********************************
// Public interface
/** Adds a new parameter to the list. */
public void addParameter(
String name,
String value) {
if (done)
throw new IllegalStateException();
if (name != null) {
names.add(name);
if (value != null)
values.add(value);
else
values.add("");
}
}
public String aggregateParams(
String url) {
/*
* Since for efficiency we're destructive to the param lists, we don't
* want to run multiple times.
*/
done = true;
//// reverse the order of our two lists
// Collections.reverse(this.names);
// Collections.reverse(this.values);
// build a string from the parameter list
StringBuffer newParams = new StringBuffer();
for (int i = 0; i < names.size(); i++) {
newParams.append(names.get(i) + "=" + values.get(i));
if (i < (names.size() - 1))
newParams.append("&");
}
// insert these parameters into the URL as appropriate
if (newParams.length() > 0) {
int questionMark = url.indexOf('?');
if (questionMark == -1) {
return (url + "?" + newParams);
}
else {
StringBuffer workingUrl = new StringBuffer(url);
workingUrl.insert(questionMark + 1, (newParams + "&"));
return workingUrl.toString();
}
}
else {
return url;
}
}
}
/**
* springboot工具类
*
* @author li_yi_neu
* @version 1.0 May 25, 2020
*/
@Component
public class SpringBootUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
if (SpringBootUtil.applicationContext == null) {
SpringBootUtil.applicationContext = applicationContext;
}
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(
String name) {
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(
Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(
String name,
Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
/**
* 获取当前Request
*
* @return HttpServletRequest
*/
public static HttpServletRequest getHttpServletRequest() {
if ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes() != null) {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
else {
return null;
}
}
}
以上就是完整的东西了,大家可以试一试,我觉得这种方式的加载有时还是挺好用的~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。