Beetl学习总结(4)——Web集成
来源:互联网 发布:高中信息技术编程解答 编辑:程序博客网 时间:2024/06/02 21:00
4.1. Web提供的全局变量
Web集成模块向模板提供web标准的变量,做如下说明
request 中的所有attribute.在模板中可以直接通过attribute name 来引用,如在controller层 request.setAttribute("user",user),则在模板中可以直接用${user.name} .
session 提供了session会话,模板通过session["name"],或者session.name 引用session里的变量
request 标准的HTTPSerlvetRequest,可以在模板里引用request属性(getter),如${request.requestURL}。
parameter 用户读取用户提交的参数。如${parameter.userId} (仅仅2.2.7以上版本支持)
ctxPath Web应用ContextPath
servlet 是WebVariable的实例,包含了HTTPSession,HTTPSerlvetRequest,HTTPSerlvetResponse.三个属性,模板中可以通过request.response,session 来引用,如 ${serlvet.request.requestURL};
所有的GroupTemplate的共享变量
pageCtx是一个内置方法 ,仅仅在web开发中,用于设置一个变量,然后可以在页面渲染过程中,调用此api获取,如pageCtx("title","用户添加页面"),在其后任何地方,可以pageCtx("title") 获取该变量。(仅仅2.2.7以上版本支持)
你可以在模板任何地方访问这些变量
如果你需要扩展更多属性,你也可以配置beetl.properties配置文件的WEBAPP_EXT属性,实现WebRenderExt接口,在渲染模板之前增加自己的扩展,如:
12
RESOURCE.root=/WEB-INF/viewsWEBAPP_EXT = com.park.oss.util.GlobalExt
1 2 3 4 5 6 7 8 910
public class GlobalExt implements WebRenderExt{ static long version = System.currentTimeMillis(); @Override public void modify(Template template, GroupTemplate arg1, HttpServletRequest arg2, HttpServletResponse arg3) { //js,css 的版本编号 template.binding("sysVersion",version); }}
这样,每次在模板里都可以访问变量sysVersion了,不需要再controller里设置,或者通过servlet filter来设置
4.2. 集成技术开发指南
Beetl默认提供了WebRender用于帮助web集成开发,所有内置的集成均基于此方法。如果你认为Beetl内置的各个web框架集成功能不够,你可以继承此类,或者参考此类源码重新写,其代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
package org.beetl.ext.web;import java.io.IOException;import java.io.OutputStream;import java.io.Writer;import java.util.Enumeration;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.beetl.core.GroupTemplate;import org.beetl.core.Template;import org.beetl.core.exception.BeetlException;/** * 通常web渲染的类,将request变量赋值给模板,同时赋值的还有session,request,ctxPath * 其他框架可以继承此类做更多的定制 * @author joelli * */public class WebRender{ GroupTemplate gt = null; public WebRender(GroupTemplate gt) { this.gt = gt; } /** * @param key 模板资源id * @param request * @param response * @param args 其他参数,将会传给modifyTemplate方法 */ public void render(String key, HttpServletRequest request, HttpServletResponse response, Object... args) { Writer writer = null; OutputStream os = null; try { // response.setContentType(contentType); Template template = gt.getTemplate(key); Enumeration<String> attrs = request.getAttributeNames(); while (attrs.hasMoreElements()) { String attrName = attrs.nextElement(); template.binding(attrName, request.getAttribute(attrName)); } WebVariable webVariable = new WebVariable(); webVariable.setRequest(request); webVariable.setResponse(response); webVariable.setSession(request.getSession()); template.binding("session", new SessionWrapper(webVariable.getSession())); template.binding("servlet", webVariable); template.binding("request", request); template.binding("ctxPath", request.getContextPath()); modifyTemplate(template, key, request, response, args); String strWebAppExt = gt.getConf().getWebAppExt(); if(strWebAppExt!=null){ WebRenderExt renderExt = this.getWebRenderExt(strWebAppExt); renderExt.modify(template, gt, request, response); } if (gt.getConf().isDirectByteOutput()) { os = response.getOutputStream(); template.renderTo(os); } else { writer = response.getWriter(); template.renderTo(writer); } } catch (IOException e) { handleClientError(e); } catch (BeetlException e) { handleBeetlException(e); } finally { try { if (writer != null) writer.flush(); if (os != null) { os.flush(); } } catch (IOException e) { handleClientError(e); } } } /** * 可以添加更多的绑定 * @param template 模板 * @param key 模板的资源id * @param request * @param response * @param args 调用render的时候传的参数 */ protected void modifyTemplate(Template template, String key, HttpServletRequest request, HttpServletResponse response, Object... args) { } /**处理客户端抛出的IO异常 * @param ex */ protected void handleClientError(IOException ex) { //do nothing } /**处理客户端抛出的IO异常 * @param ex */ protected void handleBeetlException(BeetlException ex) { throw ex; }}
4.3. Serlvet集成
只需要在Servlet代码里引用ServletGroupTemplate就能集成Beetl,他提供了一个render(String child, HttpServletRequest request, HttpServletResponse response)方法。例子如下:
1 2 3 4 5 6 7 8 910
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); //模板直接访问users request.setAttribute("users",service.getUsers()); ServletGroupTemplate.instance().render("/index.html", request, response); }
ServletGroupTemplate同其他web集成一样,将读取配置文件来配置,如果需要通过代码配置,可以在Serlvet listener里 ServletGroupTemplate.instance().getGroupTemplate()方法获取GroupTemplate
4.4. SpringMVC集成
需要做如下配置即可
123456
<bean id="beetlConfig" class="org.beetl.ext.spring.BeetlGroupUtilConfiguration" init-method="init"/><bean id="viewResolver" class="org.beetl.ext.spring.BeetlSpringViewResolver"> <property name="contentType" value="text/html;charset=UTF-8"/></bean>
同其他集成方式一样,模板的配置将放在beetl.properties中。
如果想获取GroupTemplate,可以调用如下代码
123
BeetlGroupUtilConfiguration config = (BeetlGroupUtilConfiguration) this.getApplicationContext().getBean( "beetlConfig");GroupTemplate group = config.getGroupTemplate();
Controller代码如下:
1234567
@RequestMapping(value = "/", method = RequestMethod.GET)public ModelAndView index(HttpServletRequest req) { ModelAndView view = new ModelAndView("/index"); //total 是模板的全局变量,可以直接访问 view.addObject("total",service.getCount()); return view;}
http://git.oschina.net/xiandafu/springbeetlsql 有完整例子
4.5. SpringMVC集成高级
spring集成还允许注册被spring容器管理的Function,Tag等,也还允许配置多个视图解析器等功能
1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435
<bean name="beetlConfig" class="org.beetl.ext.spring.BeetlGroupUtilConfiguration" init-method="init"> <property name="configFileResource" value="/WEB-INF/beetl.properties"/> <property name="functions"> <map> <entry key="testFunction" value-ref="testFunction"/> </map> </property> <property name="functionPackages"> <map> <entry key="fp" value-ref="testFunctionPackage"/> </map> </property> <property name="tagFactorys"> <map> <entry key="html.output" value-ref="testTagFactory"/> <entry key="html.output2" value-ref="testTagFactory2"/> </map> </property></bean><bean name="testTagFactory" class="org.beetl.ext.spring.SpringBeanTagFactory"> <property name="name" value="testTag"/></bean><bean name="testTagFactory2" class="org.beetl.ext.spring.SpringBeanTagFactory"> <property name="name" value="testTag2"/></bean><bean name="beetlViewResolver" class="org.beetl.ext.spring.BeetlSpringViewResolver"> <property name="config" ref="beetlConfig"/> <property name="contentType" value="text/html;charset=UTF-8"/></bean>
如上图所示,BeetlGroupUtilConfiguration有很多属性,列举如下
configFileResource 属性指定了配置文件所在路径,如果不指定,则默认在classpath下
functions 指定了被spring容器管理的function,key为注册的方法名,value-ref 指定的bean的名称
functionPackages,指定了被spring容器管理的functionPackage,key为注册的方法包名,value-ref 指定的bean的名称
tagFactorys ,注册tag类,key是tag类的名称,value-ref指向一个org.beetl.ext.spring.SpringBeanTagFactory实例,该子类是一个Spring管理的Bean。属性name对应的bean就是tag类。需要注意,由于Tag是有状态的,因此,必须申明Scope为 "prototype"。如代码:
1234
@Service@Scope("prototype")public class TestTag extends Tag {}
typeFormats: 同functions,参数是 Map<Class<?>, Format>,其中key为类型Class
formats:同functions,参数是 Map<String, Format>,其中key为格式化函数名
virtualClassAttributes 同functions,参数Map<Class<?>, VirtualClassAttribute>,其中key为类型Class
virtualAttributeEvals ,类型为List<VirtualAttributeEval>
resourceLoader,资源加载器 ,值是 实现ResourceLoader的一个Bean
errorHandler ,错误处理,值是实现ErrorHandler的一个Bean
sharedVars,同functions,类型是Map<String, Object>,可以在此设置共享变量
configProperties,类型是Properties,可以覆盖配置文件的某些属性
如下配置,指定了三个视图解析器,一个用于beetl页面渲染,一个用于cms,采用了beetl技术,另外一个一些遗留的页面采用jsp
1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435363738394041424344454647484950
<bean name="beetlConfig" class="org.beetl.ext.spring.BeetlGroupUtilConfiguration" init-method="init"> <property name="configFileResource" value="/WEB-INF/beetl.properties"/></bean><bean name="cmsbeetlConfig" class="org.beetl.ext.spring.BeetlGroupUtilConfiguration" init-method="init"> <property name="configFileResource" value="/WEB-INF/cms-beetl.properties"/></bean><!-- Beetl视图解析器1 --><bean name="beetlViewResolver" class="org.beetl.ext.spring.BeetlSpringViewResolver"> <!-- 多视图解析器,需要设置viewNames和order --> <property name="viewNames"> <list> <value>/template/**</value> </list> </property> <property name="suffix" value=".btl"/> <property name="contentType" value="text/html;charset=UTF-8"/> <property name="order" value="0"/> <!-- 多GroupTemplate,需要指定使用的bean --> <property name="config" ref="beetlConfig"/></bean><!-- Beetl视图解析器2 --><bean name="cmsBeetlViewResolver" class="org.beetl.ext.spring.BeetlSpringViewResolver"> <!-- 多视图解析器,需要设置viewNames和order --> <property name="viewNames"> <list> <value>/cmstemplate/**</value> </list> </property> <property name="contentType" value="text/html;charset=UTF-8"/> <property name="order" value="1"/> <!-- 多GroupTemplate,需要指定使用的bean --> <property name="config" ref="cmsbeetlConfig"/></bean><!-- JSP视图解析器 --><bean name="JSPViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 注意JSP的这个视图解析器order必须在最后 --> <property name="order" value="256"/> <!-- beetl配置不支持前缀,这不同于jsp 和 freemaker --> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> <property name="contentType" value="text/html;charset=UTF-8"/></bean>
Beetl视图解析器属性同spring自带的视图解析器一样,支持contentType,order,prefix,suffix等属性。
注意视图解析器里属性viewNames,这个用于判断controller返回的path到底应该交给哪个视图解析器来做。
以/template开头的是beetlViewResolver来渲染。
以/cmstemplate是交给cmsBeetlViewResolver渲染。
如果都没有匹配上,则是jsp渲染
如果你想更改此规则,你只能增加canHandle方法指定你的逻辑了。详情参考org.springframework.web.servlet.view.UrlBasedViewResolver.canHandle
对于仅仅需要redirect和forward的那些请求,需要加上相应的前缀
以"redirect:"为前缀时:表示重定向,不产生BeetlView渲染模版,而直接通过Servlet的机制返回重定向响应.redirect:前缀后面的内容为重定向地址,可以采用相对地址(相对当前url),绝对地址(完整的url),如果采用/开头的地址,会自动的在前面接上当前Web应用的contextPath,即contextPath为test的Web应用中使用redirect:/admin/login.html 实际重定向地址为 /test/admin/login.html
以"forward:"为前缀时:表示转发,不产生BeetlView渲染模版。而是直接通过Servlet的机制转发请求(关于转发和重定向的区别,请自行查看Servlet API) forward:前缀后面的内容为转发地址,一般都是以/开头相对于当前Web应用的根目录
其他集成需要注意的事项:
spring集成,请不要使用spring的 前缀配置,改用beetl的RESOURCE.ROOT 配置,否则include,layout会找不到模板
4.6. Spring Boot集成
Spring Boot 通过java config来配置 beetl需要的BeetlGroupUtilConfiguration,和 BeetlSpringViewResolver,参考代码如下
1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829
@Configurationpublic class BeetlConf { @Value("${beetl.templatesPath}") String templatesPath;//模板跟目录 @Bean(initMethod = "init", name = "beetlConfig") public BeetlGroupUtilConfiguration getBeetlGroupUtilConfiguration() { BeetlGroupUtilConfiguration beetlGroupUtilConfiguration = new BeetlGroupUtilConfiguration(); try { ClasspathResourceLoader cploder = new ClasspathResourceLoader(BeetlConf.class.getClassLoader(),templatesPath); beetlGroupUtilConfiguration.setResourceLoader(cploder); return beetlGroupUtilConfiguration; } catch (Exception e) { throw new RuntimeException(e); } } @Bean(name = "beetlViewResolver") public BeetlSpringViewResolver getBeetlSpringViewResolver(@Qualifier("beetlConfig") BeetlGroupUtilConfiguration beetlGroupUtilConfiguration) { BeetlSpringViewResolver beetlSpringViewResolver = new BeetlSpringViewResolver(); beetlSpringViewResolver.setContentType("text/html;charset=UTF-8"); beetlSpringViewResolver.setOrder(0); beetlSpringViewResolver.setConfig(beetlGroupUtilConfiguration); return beetlSpringViewResolver; } }
spring boot集成需要注意的是要添加spring-devtools.properties文件,并配置如下选项
12
restart.include.beetl=/beetl-xxx.jarrestart.include.beetlsql=/beetlsql-xxx..jar
spring-devtools.properties 为spring boot的配置文件,位于META-INF目录下
4.7. Jodd集成
需要配置web.xml,将所有请求交给jodd处理,参考:http://jodd.org/doc/madvoc/setup.html
1 2 3 4 5 6 7 8 91011121314151617
<filter> <filter-name>madvoc</filter-name> <filter-class>jodd.madvoc.MadvocServletFilter</filter-class> <init-param> <param-name>madvoc.webapp</param-name> <param-value>test.MyWebApplication</param-value> </init-param> <init-param> <param-name>madvoc.configurator</param-name> <param-value>test.MyAutomagicMadvocConfigurator</param-value> </init-param></filter><filter-mapping> <filter-name>madvoc</filter-name> <url-pattern>/*</url-pattern></filter-mapping>
MyWebApplication 和 MyAutomagicMadvocConfigurator 需要自己参照如下例子写一个,前者用来设置beetl作为视图渲染,后者配置Jodd不要扫描beetl struts集成里引用的struts类
123456789
public class MyAutomagicMadvocConfigurator extends AutomagicMadvocConfigurator { public MyAutomagicMadvocConfigurator(){ super(); //不扫描beetl 里jar文件里的action和result,否则,会扫描StrutsResultSupport不相干的class this.rulesJars.exclude("**/*beetl*.jar"); }}
12345678
public class MyWebApplication extends WebApplication{ @Override protected void init(MadvocConfig madvocConfig, ServletContext servletContext) { //设置默认 madvocConfig.setDefaultActionResult(BeetlActionResult.class); } }
最后,可以写Action了,浏览器输入/index.html,jodd将执行world方法,并渲染ok.html模板。如果你想配置GroupTemplate,正如其他集成框架一样,只需要写一个beetl.properties 即可。
1 2 3 4 5 6 7 8 9101112
@MadvocActionpublic class IndexAction { @Out String value; @Action("/index.html") public String world() { value = "Hello World!"; return "/ok.html"; }}
https://git.oschina.net/xiandafu/beetl-jodd-sample 有完整例子
4.8. JFinal集成
Beetl提供 JFinal 集成,使用BeetlRenderFactory ,通过如下注册即可使用beetl模板引擎
1 2 3 4 5 6 7 8 91011
import org.beetl.ext.jfinal.BeetlRenderFactorypublic class DemoConfig extends JFinalConfig{ public void configConstant(Constants me) { me.setMainRenderFactory(new BeetlRenderFactory()); // 获取GroupTemplate ,可以设置共享变量等操作 GroupTemplate groupTemplate = BeetlRenderFactory.groupTemplate ;}
业务逻辑代码:
123456789
public void modify(){ int artId = getParaToInt(0, -1); setAttr("title", "修改文章"); List<Cate> cateLists = Cate.getAllCate(); //模板里访问cateLists,atr, setAttr("cateLists", cateLists); setAttr("art", Article.dao.findById(artId)); render("/modify.html"); }
BeetlRenderFactory 默认使用FileResourceLoader ,其根目录位于WebRoot目录下,如果你需要修改到别的目录,可以设置配置文件,如
1
RESOURCE.root= /WEB-INF/template/
https://git.oschina.net/xiandafu/beetl-jfinal-sample 有完整例子,采用jfinal+beetl写的一个博客系统
4.9. Nutz集成
Nutz集成提供了 BeetlViewMaker ,实现了 ViewMaker方法,如下代码
1 2 3 4 5 6 7 8 91011
@At("/ctx") @Ok("beetl:ctx.btl") public Context withContext() { Context ctx = Lang.context(); Pager pager = dao.createPager(1, 20); pager.setRecordCount(dao.count(UserProfile.class)); List<UserProfile> list = dao.query(UserProfile.class, null, pager); ctx.set("pager", pager); ctx.set("list", list); return ctx; }
1 2 3 4 5 6 7 8 9101112131415
<html><head><title>Beetl&Nutz</title></head><body><p>总共 ${list.~size}<p/><%for(user in list){%><p>hello,${user.nickname};<p/><%}%><p>当前页${pager.pageNumber},总共${pager.pageCount}页<p/></body></html>
需要注意的是,如果使用了nutz的obj(http://www.nutzam.com/core/mvc/view.html),则需要在模板顶部申明obj是动态对象,如
123456
<%directive dynamic obj%>${obj.user.title}${obj.user.name}
4.10. Struts2集成
需要在struts2配置文件里添加result-types做如下配置
1 2 3 4 5 6 7 8 91011121314151617
<package name="default" namespace="/" extends="struts-default">.......<result-types> <result-type name="beetl" class="org.beetl.ext.struts2.Struts2BeetlActionResult" default="true" > <param name="contentType">text/html; charset=UTF-8</param> </result-type></result-types><action name="HelloWorld" class="com.beetl.struts.HelloWorld"> <result>/hello.html</result></action><action name="Ajax" class="com.beetl.struts.AjaxHtml"> <result>/table.html#table</result></action>........</package>
该类会根据struts配置文件获取模板,如上例的hello.html,并将formbean的属性,以及request属性作为全局变量传递给模板
https://git.oschina.net/xiandafu/beetl-struts2-sample 有完整例子
4.11. 直接Web中运行Beetl模板
对于web应用来说,必须通过controller才能渲染模板,beetl也可以写完模板后,在未完成controller情况下,直接渲染模板 此方法既可以作为通常的全栈式开发人员使用,也可以用于前端人员单独开发模板用。
步骤如下:
配置监听器,监听器指定对*.btl的请求进行监听(假定模板名字都是以btl.结尾)。
实现监听器,该监听器继承父类 org.beetl.ext.web.SimpleCrossFilter,实现protected abstract GroupTemplate getGroupTemplate()方法。依据不同的集成方式,比如你的环境是Servlet,则只需要调用ServletGroupTemplate.instance().getGroupTemplate(),如果是Jfinal,需要调用BeetlRenderFactory.groupTemplate等
SimpleCrossFilter 提供一些有用的方法,可以帮助你定制一些特性,可以参考源码了解
置完成后,对于要测试的模板,可以新建一个对应的伪模型文件,比如要测试模板WebRoot/user/userList.html,可以新建立WebRoot/values/user/userList.html.var 。 values是监听器默认的伪模型的根目录
编辑伪模型文件,对应于userList.html需要的全局变量,userList.html.var可以申明这些些变量
123
var proudct = {id:1,name:'测试产品',pic:'xxxx.jpg'};var userList = [{id:2,name:'用户一'}];var session= {admin:{id:1,name:'admin'}};
通过浏览器直接访问http://ip:port/user/userList.html,监听器会预先执行userList.html.var,并将返回值作为模板的全局变量,传给userList.html
可以将一些公共的变量放到WebRoot/values/common.var里(比如上面代码的session). 监听器会先执行common.var,然后再执行userList.html.var
4.12. 整合ajax的局部渲染技术
越来越多web网站依赖于ajax,如table的翻页,流行方式是浏览器发出ajax请求,后台处理后返回一个json,浏览器端将json数据拆开,拼成一条一条的行数据,然后生成dom节点,追加到表格里。 作为另外一种可选技术,beetl支持局部渲染技术,允许后台处理返回的是一个完成的html片段,这样,前端浏览器可以直接将这个html片段追加到表格里。在我做的性能测试里,俩种方式性能差别不大(http://beetlajax.oschina.mopaas.com/)
比如模板index.html有很多动态内容,有动态生成的菜单,有右侧的top10,也有核心区域的表格,大概内容如下
1 2 3 4 5 6 7 8 9101112131415161718192021
<#menu/><#top10> ....</#top10><div id="table-container" ><%//ajax片段开始#ajax userTable: {%><table> <tr><td width=100>id</td><td width=100>姓名</td></tr> <%for(user in users){%> <tr><td>${user.id}</td><td>${user.name}</td></tr> <%}%></table>当前页面<span id="current">${page!1}</span><span style="width:20px"></span><a href="#"><span class="page">next</span></a> <a href="#" ><span class="page">pre</span></a><%//ajax片段结尾}%>
#ajax 用于告诉告诉模板引擎,此处是个局部渲染标记,标记为"userTable",对于正常渲染视图"index.html"页面,#ajax标记没什么用处,table仍能得到正常渲染。如果渲染的视图是index.html#userTable,则模板只会渲染#ajax标记得模板片段,其他部分将忽略。关于完整例子,可以参考http://beetlajax.oschina.mopaas.com/
后台代码如下:
1
render("/index.html#userTable");
ajax 片段渲染也支持默认情况下不渲染,仅仅做为一个片段使用,如一个页面有许多后台交互操作,并返回相应的html片段,可以将这些html片段也放到同一个模板里,使用ajax norender,表示渲染整个模板的时候默认并不需要渲染此ajax片段
1 2 3 4 5 6 7 8 9101112131415161718192021
<%<html></html>#ajax norender success: {%><div id="success"> 操作成功</div><%}%>#ajax norender failure: {%><div id="failure"> 操作失败</div><%}%>
这样,此页面默认情况下并没有输出success,和 failure片段
4.13. 在页面输出错误提示信息
2.2.3版本以后,新增加org.beetl.ext.web.WebErrorHandler,可以在web开发的时候在页面输出提示信息,在产品模式下载后台输出提示信息(通过配置属性ESOURCE.autoCheck= true来认为是开发模式),仅仅需要配置如下:
1
ERROR_HANDLER = org.beetl.ext.web.WebErrorHandler
- Beetl学习总结(4)——Web集成
- Beetl学习总结(1)——新一代java模板引擎典范 Beetl入门
- Beetl学习总结(2)——基本用法
- Beetl学习总结(3)——高级功能
- jfinal +beetl集成开发web全集
- Shiro学习笔记(5)——web集成
- Shiro 学习笔记(7)—— Shiro 集成 Web
- JFinal集成Beetl静态模板
- JFinal集成Beetl静态模板
- JFinal集成Beetl静态模板
- JFinal集成Beetl静态模板
- MyBatis学习总结(二)——SpringMVC+Spring4+Mybatis3集成,开发简单Web项目+源码下载
- 学习新知识 beetl beetl和shiro
- Shiro学习总结(10)——Spring集成Shiro
- 集成学习——Boosting总结
- AppFuse——集成Web框架开发总结(J2EE)
- Jenkins学习总结(4)——持续集成,持续交付,持续部署之间的区别
- 学习笔记——Maven实战(五)自动化Web应用集成测试
- linux编程—who命令编写
- 深度卷积神经网络的14种设计模式
- Svn右键不出现svn checkout 图标
- spring连接access数据库
- 大型分布式网站架构技术总结
- Beetl学习总结(4)——Web集成
- hadoop环境搭建
- 在Tomcat中单独发布网页的三种方法
- 使用USART接口进行STM32F0的在线升级(AN4065)-基于标准库的STM32F070的IAP移植手记
- usaco Healthy Holsteins
- 查看使用 npm 安装插件的版本号
- 1.android深入研讨,四种启动模式
- 将其他远程仓库的代码合并到本地,并将本地仓库的代码提交到其他远程仓库
- 集成Dubbo服务(Spring)