当前位置: 首页 > 编程日记 > 正文

struts2请求处理过程源代码分析(1)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

转载自:http://www.see-source.com/ 源码解析网

网上对于struts2请求处理流程的讲解还是比较多的,有的还是非常详细的,所以这里我就简单地将大概流程总结下,有了个大概印象后理解起源码就会有一定的思路了:

struts2的请求处理过程实际上是在初始化中加载的配置及容器的基础上,通过请求的url分析出命名空间、action名称、方法名称,在利用命名空间检索出该命名空间下配置的所有antion,在通过action名称找到具体的action,生成action实例,如果该action上配置了拦截器则依次调用拦截器,之后调用action中方法名称指定的方法,最后通过配置中的result返回相应视图。

版本:struts2-2.1.6  xwork-2.1.2

下面就通过源码进行分析下:

struts2中处理请求是通过过滤器org.apache.struts2.dispatcher.FilterDispatcher的doFilter()方法实现的,如下:


public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) res;ServletContext servletContext = getServletContext();String timerKey = "FilterDispatcher_doFilter: ";try {// FIXME: this should be refactored better to not duplicate work with the action invocationValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();ActionContext ctx = new ActionContext(stack.getContext());ActionContext.setContext(ctx);UtilTimerStack.push(timerKey);request = prepareDispatcherAndWrapRequest(request, response);ActionMapping mapping;try {mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());} catch (Exception ex) {log.error("error getting ActionMapping", ex);dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);return;}if (mapping == null) {// there is no action in this request, should we look for a static resource?String resourcePath = RequestUtils.getServletPath(request);if ("".equals(resourcePath) && null != request.getPathInfo()) {resourcePath = request.getPathInfo();}if (staticResourceLoader.canHandle(resourcePath)) {staticResourceLoader.findStaticResource(resourcePath, request, response);} else {// this is a normal request, let it pass throughchain.doFilter(request, response);}// The framework did its job herereturn;}dispatcher.serviceAction(request, response, servletContext, mapping);} finally {try {ActionContextCleanUp.cleanUp(req);} finally {UtilTimerStack.pop(timerKey);}}}

前2句比较简单,向上转换req、res为标准接口HttpServletRequest、HttpServletResponse形式。req是org.apache.catalina.connector.RequestFacade的实例,RequestFacade实现了接口HttpServletRequest,而HttpServletRequest继承自ServletRequest接口。第3句,获得servletContext即servlet上下文,通过上下文对象可以访问web.xml描述文件的初始化参数。第4句定义timerKey变量,值是将当前过滤器的类名和当前方法名拼接起来,看下下面的代码发现timerKey用于UtilTimerStack.push(timerKey)和UtilTimerStack.pop(timerKey)俩句,其实这俩句并不属于处理流程的功能代码,而是性能代码,主要是监测下doFilter()方法的执行时间,然后通过日志打印出来,所以这俩句可以不用理会。ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack()句,首先通过dispatcher.getContainer().getInstance(ValueStackFactory.class)从容器中获得type(类型)为ValueStackFactory.class的bean,然后调用该bean的createValueStack()创建一个ValueStack实例。ValueStackFactory.class默认情况下是使用struts-default.xml配置中的 <bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="struts" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />,即通过上面的容器返回的是个com.opensymphony.xwork2.ognl.OgnlValueStackFactory实例,从名字看出其是个ValueStack工厂,通过调用该工厂的createValueStack()方法返回ValueStack实例。

ValueStack就是通常所说的"值栈",系统每次请求时都会创建个新的ValueStack,其中会保存着本次请求处理的所有中间数据,如:请求的action实例、各种servlet内置对象(request、response、session、application等)、请求参数等。F5看下定义:


public interface ValueStack {public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";public static final String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";public abstract Map<String, Object> getContext();public abstract void setDefaultType(Class defaultType);public abstract void setExprOverrides(Map<Object, Object> overrides);public abstract Map<Object, Object> getExprOverrides();public abstract CompoundRoot getRoot();public abstract void setValue(String expr, Object value);public abstract void setValue(String expr, Object value, boolean throwExceptionOnFailure);public abstract String findString(String expr);public abstract Object findValue(String expr);public abstract Object findValue(String expr, Class asType);public abstract Object peek();public abstract Object pop();public abstract void push(Object o);public abstract void set(String key, Object o);public abstract int size();}
是个接口,因为ValueStack本身是堆栈,所以我们看到peek()、pop()、push()等堆栈方法都是有的,其中有个最重要的方法getContext()和getRoot(),getContext()返回的是个Map<String, Object>类型,一般请求中的参数、servlet各种内置对象都是存放在这个Map中。getRoot()返回的就是堆栈数据实际存放的地方,peek()、pop()、push()都是基于其操作的。CompoundRoot是个堆栈类,它继承了java.util.ArrayList,并以此为基础实现了peek()、pop()、push()方法,从而可以独立的作为堆栈使用。这样的话ValueStack就不必在单独实现堆栈功能,只需要在内部创建个CompoundRoot实例就可,其peek()、pop()、push()方法直接调用CompoundRoot的相应方法即可,实际上struts2中的 ValueStack默认实现类就是这样做的。另外在这个堆栈中保存的最典型的数据就是action实例。有ognl知识的朋友知道,ognl中基于搜索的有俩个重要对象:上下文和根对象,实际上struts2在利用ognl时,是将getContext()获得的对象作为ognl的上下文、getRoot()获得的作为根对象。这就是为什么我们在通过struts2标签访问action中属性数据时不需要加"#",而访问request、response、session中数据时需要加"#"的原因了。因为ognl中访问根对象是不需要加"#"的,而访问上下文是需要加"#"的。为了更好的理解这块,建议大家先学习下ognl的使用方法及特性。为了验证上面的说法,我举个例子,看下struts2的<s:property value=""/>标签是如何使用ValueStack的,以及最后如何调用ognl的。


这里还要事先交代下,在处理流程的后面处理中会将ValueStack(引用)存于俩个地:一个是ActionContext,另一个是通过request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, valuesStack)将ValueStack存于request中。<s:property value=""/>标签中使用的ValueStack是通过request获得的。下面看下<s:property value=""/>标签的源码,从struts2的标签定义文件struts-tags.tld中查到,该标签对应的类是org.apache.struts2.views.jsp.PropertyTag,如下:


public class PropertyTag extends ComponentTagSupport {private static final long serialVersionUID = 435308349113743852L;private String defaultValue;private String value;private boolean escape = true;private boolean escapeJavaScript = false;public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {return new Property(stack);}protected void populateParams() {super.populateParams();Property tag = (Property) component;tag.setDefault(defaultValue);tag.setValue(value);tag.setEscape(escape);tag.setEscapeJavaScript(escapeJavaScript);}public void setDefault(String defaultValue) {this.defaultValue = defaultValue;}public void setEscape(boolean escape) {this.escape = escape;}public void setEscapeJavaScript(boolean escapeJavaScript) {this.escapeJavaScript = escapeJavaScript;}public void setValue(String value) {this.value = value;}
}
我们要找下标签的doStartTag(),这个方法会在标签被处理前调用。关于标签这块,建议大家先学下jsp自定义标签的使用。

去它的父类ComponentTagSupport中找下:


public abstract class ComponentTagSupport extends StrutsBodyTagSupport {protected Component component;public abstract Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res);public int doEndTag() throws JspException {component.end(pageContext.getOut(), getBody());component = null;return EVAL_PAGE;}public int doStartTag() throws JspException {component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());Container container = Dispatcher.getInstance().getContainer();container.inject(component);populateParams();boolean evalBody = component.start(pageContext.getOut());if (evalBody) {return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;} else {return SKIP_BODY;}}protected void populateParams() {}public Component getComponent() {return component;}
}

找到了。doStartTag()方法第1句,调用getBean(),其中有个参数调用了getStack(),实际上这个方法返回的就是我上面说的ValueStack。F5进入:


public class StrutsBodyTagSupport extends BodyTagSupport {private static final long serialVersionUID = -1201668454354226175L;protected ValueStack getStack() {return TagUtils.getStack(pageContext);}...//省略
}

该方法是在ComponentTagSupport的父类StrutsBodyTagSupport中。其中只有一句TagUtils.getStack(pageContext),pageContext就是servlet的页面上下文内置对象,F5进入TagUtils.getStack(pageContext):


public static ValueStack getStack(PageContext pageContext) {HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();ValueStack stack = (ValueStack) req.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);if (stack == null) {HttpServletResponse res = (HttpServletResponse) pageContext.getResponse();Dispatcher du = Dispatcher.getInstance();if (du == null) {throw new ConfigurationException("The Struts dispatcher cannot be found.  This is usually caused by "+"using Struts tags without the associated filter. Struts tags are only usable when the request "+"has passed through its servlet filter, which initializes the Struts dispatcher needed for this tag.");}stack = du.getContainer().getInstance(ValueStackFactory.class).createValueStack();Map<String, Object> extraContext = du.createContextMap(new RequestMap(req),req.getParameterMap(),new SessionMap(req),new ApplicationMap(pageContext.getServletContext()),req,res,pageContext.getServletContext());extraContext.put(ServletActionContext.PAGE_CONTEXT, pageContext);stack.getContext().putAll(extraContext);req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);// also tie this stack/context to the ThreadLocalActionContext.setContext(new ActionContext(stack.getContext()));} else {// let's make sure that the current page context is in the action contextMap<String, Object> context = stack.getContext();context.put(ServletActionContext.PAGE_CONTEXT, pageContext);AttributeMap attrMap = new AttributeMap(context);context.put("attr", attrMap);}return stack;}

方法第1句,通过页面上下文对象pageContext获得本次请求的request对象,第2句在通过req.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY)获得ValueStack,因为事先struts2已经通过request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, valuesStack)将ValueStack存于request的ServletActionContext.STRUTS_VALUESTACK_KEY属性中,所以通过第2句就可以获得ValueStack,直接return stack返回到ComponentTagSupport类的doStartTag()方法,如下(我在把代码粘下):


public int doStartTag() throws JspException {component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());Container container = Dispatcher.getInstance().getContainer();container.inject(component);populateParams();boolean evalBody = component.start(pageContext.getOut());if (evalBody) {return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;} else {return SKIP_BODY;}}

执行完getStack()接着看getBean()方法,在ComponentTagSupport类中可以找到,getBean()方法被定义为抽象方法,所以具体的实现要在其子类PropertyTag中找,F5进入:


public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {return new Property(stack);}

方法只有一句通过new 生成了Property实例,同时将stack作为构造参数传进去,这个stack就是我们上面通过getStack()得到的ValueStack,执行完后程序会重新回到ComponentTagSupport类的doStartTag()方法,我把代码在粘下:


public int doStartTag() throws JspException {component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());Container container = Dispatcher.getInstance().getContainer();container.inject(component);populateParams();boolean evalBody = component.start(pageContext.getOut());if (evalBody) {return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;} else {return SKIP_BODY;}}

这样component中实际引用的就是Property实例,第2、3句,调用容器,通过container.inject(component)将Property中需要注入的属性赋值(带有@Inject标注的)。populateParams()句将标签属性添加到component相应属性中,如value、escape。核心在下面这句component.start(pageContext.getOut()),通过ognl访问ValueStack从而获得标签的value值,F5进入Property的start():


public boolean start(Writer writer) {boolean result = super.start(writer);String actualValue = null;if (value == null) {value = "top";}else {value = stripExpressionIfAltSyntax(value);}// exception: don't call findString(), since we don't want the//            expression parsed in this one case. it really//            doesn't make sense, in fact.actualValue = (String) getStack().findValue(value, String.class);try {if (actualValue != null) {writer.write(prepare(actualValue));} else if (defaultValue != null) {writer.write(prepare(defaultValue));}} catch (IOException e) {LOG.info("Could not print out value '" + value + "'", e);}return result;}

直接看(String) getStack().findValue(value, String.class)  调用getStack()获得ValueStack,这个ValueStack实在Property实例生成时通过构造方法传入的。之后调用ValueStack的findValue()方法, 其中参数value就是<s:property value=""/>标签的value属性值。我们在上面说过ValueStack的实现类默认使用的是com.opensymphony.xwork2.ognl.OgnlValueStack类,F5进入其findValue():


public Object findValue(String expr, Class asType) {try {if (expr == null) {return null;}if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);}Object value = ognlUtil.getValue(expr, context, root, asType);if (value != null) {return value;} else {return findInContext(expr);}} catch (OgnlException e) {return findInContext(expr);} catch (Exception e) {logLookupFailure(expr, e);return findInContext(expr);} finally {ReflectionContextState.clear(context);}}

直接看ognlUtil.getValue(expr, context, root, asType)句,可以看到content、root就是我们上面说的ValueStack中getContext()和getRoot()方法中对应的属性值,我们说过它分别对应ognl中的上下文和根对象。ognlUtil是com.opensymphony.xwork2.ognl.OgnlUtil类的实例,是struts2中用于操作ognl而单独封装的管理类, F5进入ognlUtil.getValue()方法:


public Object getValue(String name, Map<String, Object> context, Object root, Class resultType) throws OgnlException {return Ognl.getValue(compile(name), context, root, resultType);}
实际上,上面的方法只是将name做处理后直接调用ognl的getValue()方法。context作为ognl的上下文,root作为ognl的根对象,name是属性名。此时的root中就存放着当前action的实例。return返回的值就是<s:property value=""/>标签最终所获得的值。说道这熟悉ognl的应该已经明白了。









转载于:https://my.oschina.net/u/1023981/blog/119429

相关文章:

Ubuntu中C代码静态检查工具Splint的安装配置和使用

1、 从http://www.splint.org/download.html下载splint-3.1.2.src.tgz&#xff0c;存放到/home/spring/Splint文件夹下&#xff1b; 2、 打开终端&#xff1b; 3、 解压缩&#xff1a;tar zxvfsplint-3.1.2.src.tgz 4、 安装到/usr/local/splint目录下&#xff1a; …

Fetch 入门

一、什么是Fetch &#xff1f; Fetch的定义 Fetch本质上是一种标准&#xff0c;该标准定义了请求、响应和绑定的流程。 Fetch标准还定义了Fetch () JavaScript API&#xff0c;它在相当低的抽象级别上公开了大部分网络功能&#xff0c;我们今天讲的主要是Fetch API。Fetch API …

保障数据安全,强调科技向善,旷视发布《人工智能应用准则》

目录 AI应用落地加速 善用科技是关键 《人工智能应用准则》全文 2019年7月17日&#xff0c;旷视正式全文公布基于企业自身管理标准的《人工智能应用准则》&#xff08;以下简称《准则》&#xff09;。《准则》从正当性、人的监督、技术可靠性和安全性、公平和多样性、问责和及…

胜者树和败者树 - qianye0905 - 博客园

胜者树和败者树 - qianye0905 - 博客园胜者树和败者树胜者树和败者树都是完全二叉树&#xff0c;是树形选择排序的一种变型。每个叶子结点相当于一个选手&#xff0c;每个中间结点相当于一场比赛&#xff0c;每一层相当于一轮比赛。不同的是&#xff0c;胜者树的中间结点记录的…

C/C++代码静态检查工具PC-lint在VS2008开发环境中的安装配置和使用

PC-Lint偏重于代码的逻辑分析&#xff0c;它能够发现代码中潜在的错误&#xff0c;比如数组访问越界、内存泄漏、使用未初始化变量等。 1、 从http://download.csdn.net/detail/liuchang5/3005191 下载破解版PC-lint9.0&#xff1b; 2、 解压缩到D:\soft\PC-lint&#xff0c…

k8s使用kube-router网络插件并监控流量状态

简介 kube-router是一个新的k8s的网络插件&#xff0c;使用lvs做服务的代理及负 载均衡&#xff0c;使用iptables来做网络的隔离策略。部署简单&#xff0c;只需要在每个节点部署一个daemonset即可&#xff0c;高性能&#xff0c;易维护。支持pod间通信&#xff0c;以及服务的代…

作业盒子完成1.5亿美元D轮融资,更名“小盒科技”

作者 | 夕颜 导读&#xff1a;2019 年 7 月 18 日&#xff0c;AI 在线教育创企“作业盒子”召开发布会&#xff0c;宣布已于今年 5 月完成 1.5 亿美元 D 轮融资&#xff0c;由阿里巴巴领投。同时&#xff0c;“作业盒子”宣布进行品牌升级&#xff0c;正式更名为“小盒科技”&a…

8500WN流畅高速上网高端卡 12核心不锁倍频

据台湾媒体最新报道&#xff0c;台湾无线网卡厂商最新推出一款大功率80DBI无线网卡-横空出世8500WN集成机。售价约1180新台币(折合人民币约298元) 台湾卡王是全球著名的大功率无线网卡生产厂商&#xff0c;2007年曾最早推出大功率无线网卡8G&#xff0c;以其卓越的品质&#xf…

Fiddler抓包工具总结(转)

序章 Fiddler是一个蛮好用的抓包工具&#xff0c;可以将网络传输发送与接受的数据包进行截获、重发、编辑、转存等操作。也可以用来检测网络安全。反正好处多多&#xff0c;举之不尽呀&#xff01;当年学习的时候也蛮费劲&#xff0c;一些蛮实用隐藏的小功能用了之后就忘记了&a…

Windows 64位机上C/C++代码静态检查工具Logiscope RuleChecker的安装和使用

1、 从http://download.csdn.net/detail/zmywly/3611820 和 http://download.csdn.net/detail/zmywly/3611854下载破解版&#xff1b; 2、 将文件解压缩到D:\soft\logiScope文件夹下&#xff0c;会生成一个logiScope[6.1.30]文件夹&#xff1b; 3、 双击D:\soft\lo…

作业盒子完成1.5亿美元D轮融资,用AI普及教育资源

作者 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;导读&#xff1a;2019 年 7 月 18 日&#xff0c;AI 在线教育创企“作业盒子”召开发布会&#xff0c;宣布已于今年 5 月完成 1.5 亿美元 D 轮融资&#xff0c;由阿里巴巴领投。同时&#xff0c;“作业盒子…

迭代器接口IteratorAggregate 与类 ArrayIterator(转)

也许你很想使用foreach来遍历一个类中的属性&#xff0c;然而你却没有很好的方式来这么做。可能使用PHP中class的操作的方式能够帮助你实现一些&#xff0c;但是现在我想你有了更好的方式。通过继承接口&#xff1a;IteratorAggregate来实现。 示例 [php] view plaincopy <?…

整理《Mastering OpenCV with Practical Computer Vision Projects》中第8章用Eigenfaces或Fisherfaces进行人脸识别操作流程

These generally involve four main steps&#xff1a;(1)、Face detection&#xff1b;(2)、Face preprocessing&#xff1b;(3)、Collect and learn faces&#xff1b;(4)、Face recognition. 一、Face detection(Haar-based、LBP-based) LBP-based detectors are potential…

性能比GPU高100倍!华人教授研发全球首个可编程忆阻器AI计算机

译者 | 陆离责编 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;导读&#xff1a;近日&#xff0c;密歇根大学研发成功第一台可编程的忆阻器计算机&#xff0c;它不仅是一个通过外部计算机运行的忆阻器阵列&#xff0c;而且还是可以在智能手机等小型设备上进行…

深入解析redis cluster gossip机制

社区版redis cluster是一个P2P无中心节点的集群架构&#xff0c;依靠gossip协议传播协同自动化修复集群的状态。本文将深入redis cluster gossip协议的细节&#xff0c;剖析redis cluster gossip协议机制如何运转。协议解析 cluster gossip协议定义在在ClusterMsg这个结构中&am…

Python 3.8即将发布,这几个变化你必须知道

作者 | Jake Edge译者 | Rachel出品 | Python大本营&#xff08;ID:pythonnews&#xff09;【导读】近日&#xff0c; Python 3.8.0b1 版本和 beta 版相继发布&#xff0c; Python 3.8 版的新特征已经基本成型。尽管最终版本的官方发布时间为 10 月&#xff0c;但实际上&#x…

Ubuntu 12.10 拨号上网及停用方法

2019独角兽企业重金招聘Python工程师标准>>> 本人电脑在设置了拨号上网过后&#xff0c;本来原先插上网线就能上网&#xff0c;现在反而不能上了&#xff0c;在网上找了些办法&#xff0c;再进行了些修改&#xff0c;最后成功了&#xff0c;现在把我的方法给大家分享…

011:视图函数介绍

视图&#xff1a; 视图一般都写在 app 的 views.py 中。并且视图的第一个参数永远都是 request &#xff08;一个HttpRequest&#xff09;对象。这个对象存储了请求过来的所有信息&#xff0c;包括携带的参数以及一些头部信息等。在视图中&#xff0c;一般是完成逻辑相关的操作…

Windows XP下vs2010中配置OpenCV2.4.3

1、 从http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.4.3/下载OpenCV2.4.3&#xff1b; 2、 将OpenCV-2.4.3.exe放到D:\Soft\OpenCV2.4.3文件夹下&#xff0c;解压到当前文件夹下&#xff0c;生成一个opencv文件夹&#xff1b; 3、 下载并安装CMake&…

改变shell read命令的隔符

2019独角兽企业重金招聘Python工程师标准>>> orgIFSIFS IFS"." ls */.fst/.txt | while read var1 var2 var3 do IFS$orgIFS fstcompile --isymbols${path1}isymtab.txt --osymbols${path1}osymtab.txt ${var1}/.fst/.txt ${var1}/.fst fstdraw --isymbol…

AutoML前沿技术与实践经验分享 | 免费报名

传统机器学习的解决范式可表示为&#xff1a;ML Solution ML expertise Computation Data新机器学习范式可表示为&#xff1a;New ML Solution 100x Computation 100x Data通过表示的变化&#xff0c;可以看出&#xff0c;传统范式的“ML expertise”被“100x”的“Comput…

传承乡邦文化,展示国学之美,联墨香飘远,文明花放红;

2019独角兽企业重金招聘Python工程师标准>>> 12月16日上午&#xff0c;阳光普照&#xff0c;翰墨飘香。由揭阳市文联指导、揭阳市楹联学会主办、榕城区图书馆协办的“我们的美好生活”原创联墨作品展在榕城区图书馆隆重开幕。 此次活动意在传承乡邦文化&#xff0c;…

VS2010运行速度优化汇总

1、 工具-->选项-->环境&#xff1a;视觉体验&#xff0c;前对勾全去掉&#xff1b; 2、 工具-->选项-->环境-->启动&#xff1a;启动时(P)下拉列表框中选择&#xff1a;显示空环境&#xff1b; 3、 工具-->选项-->文本编辑器-->C/C-->高级&am…

(一)JDBC入门及简介

引用百度对JDBC的解释&#xff1a; JDBC&#xff08;Java Data Base Connectivity,java数据库连接&#xff09;是一种用于执行SQL语句的Java API&#xff0c;可以为多种关系数据库提供统一访问&#xff0c;它由一组用Java语言编写的类和接口组成。JDBC为工具/数据库开发人员提供…

OpenCV中OpenCL模块函数

It currently develop and test on GPU devices only. This includes both discrete GPUs(NVidia,AMD), as well as integrated chips(AMD APU and intel HD devices). The ocl module can be found under the “modules”directory. In “modules/ocl/src” you can find the…

这位创造GitHub冠军项目的“老男人”,堪称10倍程序员本尊

作者 | 马超&#xff0c;CSDN博客专家&#xff0c;金融科技从业者来源 | CSDN博客7月12日一款叫做TDengine的时序数据库项目在GitHub上开源了&#xff0c;这个项目一经发布就稳稳占据了GitHub排行榜的C位&#xff0c;目前TdEngine已经累积了5000多个star,并且连续一周排在上升榜…

hdu 1724 Ellipse——辛普森积分

题目&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1724 #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define db double using namespace std; const db eps1e-5; int T;db a,b,l,r; db f(db x){return sqrt(…

模仿Hibernate的逆向工程_java版_源码下载

在这篇blog&#xff1a;"Hibernate逆向工程原理_java版本"中谈到了Hibernate逆向工程原理。 我喜欢理论和实践相结合....so,今天我试着模仿hibernate的逆向工程&#xff0c;哈哈&#xff0c;我成功啦.... 话不多说....直接上图先&#xff1a; 项目结构&#xff1a; 运…

http协议进阶(三)http报文

一、报文流 http报文是在http应用程序之间发送的数据块&#xff08;也可称为数据包&#xff09;、这些数据块以一些文本的元信息&#xff08;meta-information&#xff09;开头&#xff0c;描述了报文的内容及含义&#xff0c;后面跟着 可选的数据部分&#xff0c;这些报文在客…

一行Python代码能实现什么丧心病狂的功能?

作者 | 天元浪子来源 | CSDN博客手头有 109 张头部 CT 的断层扫描图片&#xff0c;我打算用这些图片尝试头部的三维重建。基础工作之一&#xff0c;就是要把这些图片数据读出来&#xff0c;组织成一个三维的数据结构&#xff08;实际上是四维的&#xff0c;因为每个像素有 RGB…