Webx MVC

article/2025/9/29 7:45:36

首先在Webx中,使用WebxContextLoaderListener替代Spring的ContextLoaderListener:

    <listener><listener-class>com.alibaba.citrus.webx.context.WebxContextLoaderListener</listener-class></listener><filter><filter-name>webx</filter-name><filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class></filter>

其中因为在Servlet定义中,listener的初始化先于filter,所以先从WebxContextLoaderListener看起:
首先ContextLoaderListener的功能是初始化IoC容器,那么WebxContextLoaderListener也应该具有初始化IoC容器的功能:

/*** 用来启动root context的listener。* <p>* 和Spring {@link ContextLoaderListener}类似,listener将读取* <code>/WEB-INF/web.xml</code>中context param <code>contextClass</code>* 所指定的类名,作为root <code>ApplicationContext</code>的实现类。假如未明确指定,则使用默认值* {@link WebxApplicationContext}。* </p>* <p>* 默认值可以通过覆盖<code>getDefaultContextClass()</code>来改变。* </p>** @author Michael Zhou*/
public class WebxContextLoaderListener extends ContextLoaderListener {@Overrideprotected final ContextLoader createContextLoader() {return new WebxComponentsLoader() {@Overrideprotected Class<? extends WebxComponentsContext> getDefaultContextClass() {Class<? extends WebxComponentsContext> defaultContextClass = WebxContextLoaderListener.this.getDefaultContextClass();if (defaultContextClass == null) {defaultContextClass = super.getDefaultContextClass();}return defaultContextClass;}};}protected Class<? extends WebxComponentsContext> getDefaultContextClass() {return null;}
}

从源码可以看出:WebxContextLoaderListener 继承于ContextLoaderListener ,所以也具有ContextLoaderListener的功能

// 继承自ServletContextListener 
public class ContextLoaderListener implements ServletContextListener {private ContextLoader contextLoader;// Spring初始化IoC容器的入口:public void contextInitialized(ServletContextEvent event) {// WebxContextLoaderListener 重写了createContextLoader方法,其返回类型为WebxComponentsLoader,说明WebxComponentsLoader为ContextLoader的派生类。this.contextLoader = createContextLoader();// 执行WebxComponentsLoader的初始化ApplicationContext操作this.contextLoader.initWebApplicationContext(event.getServletContext());}...
}

接下来看看contextLoader的initWebApplicationContext方法执行了什么步骤

    /*** Initialize Spring's web application context for the given servlet context* 在指定Servlet上下文中初始化Spring的应用上下文*/public WebApplicationContext initWebApplicationContext(ServletContext servletContext)throws IllegalStateException, BeansException {...try {ApplicationContext parent = loadParentContext(servletContext);this.context = createWebApplicationContext(servletContext, parent);//指定Spring上下文名称servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);...return this.context;}catch (...) {...}}

现在看一下WebxComponentsContext 的实现代码:

/*** 用来初始化<code>WebxComponents</code>。** @author Michael Zhou*/
public class WebxComponentsContext extends WebxApplicationContext {private WebxComponentsLoader componentsLoader;public WebxComponentsLoader getLoader() {return assertNotNull(componentsLoader, ILLEGAL_STATE, "no WebxComponentsLoader set");}public void setLoader(WebxComponentsLoader loader) {this.componentsLoader = loader;}/** 取得所有的components。 */public WebxComponents getWebxComponents() {return getLoader().getWebxComponents();}// Webx重写Spring方法@Overrideprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);getLoader().postProcessBeanFactory(beanFactory);}// Webx重写Spring方法@Overrideprotected void finishRefresh() {super.finishRefresh();getLoader().finishRefresh();}/** 在创建子容器时,给parent一个设置子context的机会。 */protected void setupComponentContext(WebxComponentContext componentContext) {}
}

在刚才的createContextLoader方法中,生成WebxComponentsContext 实例,其继承了WebxApplicationContext,而WebxApplicationContext->ResourceLoadingXmlWebApplicationContext->XmlWebApplicationContext->org.springframework.web.context.support.XmlWebApplicationContext,对于这么一条继承关系,
在Spring的WebApplicationContext 中,比较重要的refresh函数,是整个IoC容器资源加载以及注册的关键,先回顾一下refresh函数:

public void refresh() throws BeansException, IllegalStateException {//refresh过程是同步的,线程安全synchronized (this.startupShutdownMonitor) {//容器启动的预先准备,设置startup date等prepareRefresh();//创建BeanFactory,如果已存在就先销毁。BeanFactory装载BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//配置BeanFactory的标准上下文特性prepareBeanFactory(beanFactory);try {//在bean开始装载后,提供一个修改BeanFactory的接口postProcessBeanFactory(beanFactory);//调用postBeanBeanFactoryinvokeBeanFactoryPostProcessors(beanFactory);//注册BeanPostProcessor,可以再bean初始化前后定制一些功能registerBeanPostProcessors(beanFactory);//初始化消息源initMessageSource();//初始化事件监听器集合initApplicationEventMulticaster();//用于扩展实现一些特殊的bean的初始化,默认什么都不做onRefresh();//注册监听器registerListeners();//初始化其余非延迟加载的beanfinishBeanFactoryInitialization(beanFactory);//最后一步:调用onRefresh方法,并发布ContextRefreshedEvent事件finishRefresh();}catch (BeansException ex) {...}}}

回到Webx重写Spring的方法,都先执行了Spring的WebApplicationContext方法,然后执行了Webx定义的getLoader得到的WebxComponentsLoader的postProcessBeanFactory方法

    @Overrideprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);getLoader().postProcessBeanFactory(beanFactory);}@Overrideprotected void finishRefresh() {super.finishRefresh();getLoader().finishRefresh();}

进入WebxComponentsLoader ,其实它继承自ContextLoader :

/*** 用来装载webx components的装载器。** @author Michael Zhou*/
public class WebxComponentsLoader extends ContextLoader {...private ServletContext        servletContext;private WebApplicationContext componentsContext;private WebxComponentsImpl    components;.../*** 在创建beanFactory之初被调用。** @param webxComponentsContext*/public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 由于初始化components依赖于webxConfiguration,而webxConfiguration可能需要由PropertyPlaceholderConfigurer来处理,// 此外,其它有一些BeanFactoryPostProcessors会用到components,// 因此components必须在PropertyPlaceholderConfigurer之后初始化,并在其它BeanFactoryPostProcessors之前初始化。//// 下面创建的WebxComponentsCreator辅助类就是用来确保这个初始化顺序:// 1. PriorityOrdered - PropertyPlaceholderConfigurer// 2. Ordered - WebxComponentsCreator// 3. 普通 - 其它BeanFactoryPostProcessorsBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(WebxComponentsCreator.class);builder.addConstructorArgValue(this);BeanDefinition componentsCreator = builder.getBeanDefinition();componentsCreator.setAutowireCandidate(false);BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;String name = SpringExtUtil.generateBeanName(WebxComponentsCreator.class.getName(), registry);registry.registerBeanDefinition(name, componentsCreator);}// WebxComponentsCreator 辅助类public static class WebxComponentsCreator implements BeanFactoryPostProcessor, Ordered {private final WebxComponentsLoader loader;public WebxComponentsCreator(WebxComponentsLoader loader) {this.loader = assertNotNull(loader, "WebxComponentsLoader");}public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if (loader.components == null) {WebxComponentsImpl components = loader.createComponents(loader.getParentConfiguration(), beanFactory);AbstractApplicationContext wcc = (AbstractApplicationContext) components.getParentApplicationContext();wcc.addApplicationListener(new SourceFilteringListener(wcc, components));loader.components = components;}}public int getOrder() {return Ordered.LOWEST_PRECEDENCE;}}/** 初始化所有components。 */public void finishRefresh() {components.getWebxRootController().onFinishedProcessContext();// 遍历子模块,并且执行refresh,相当于每个子模块都有一个ApplicationContextfor (WebxComponent component : components) {...WebxComponentContext wcc = (WebxComponentContext) component.getApplicationContext();WebxController controller = component.getWebxController();// refresh就是刚才提到的WebApplicationContext的那个重要的函数wcc.refresh();controller.onFinishedProcessContext();}...}/** 初始化components。 */private WebxComponentsImpl createComponents(WebxConfiguration parentConfiguration,ConfigurableListableBeanFactory beanFactory) {ComponentsConfig componentsConfig = getComponentsConfig(parentConfiguration);// 假如isAutoDiscoverComponents==true,试图自动发现componentsMap<String, String> componentNamesAndLocations = findComponents(componentsConfig, getServletContext());// 取得特别指定的componentsMap<String, ComponentConfig> specifiedComponents = componentsConfig.getComponents();// 实际要初始化的comonents,为上述两种来源的并集Set<String> componentNames = createTreeSet();componentNames.addAll(componentNamesAndLocations.keySet());componentNames.addAll(specifiedComponents.keySet());// 创建root controller,WebxRootController 在后面会分析到WebxRootController rootController = componentsConfig.getRootController();if (rootController == null) {rootController = (WebxRootController) BeanUtils.instantiateClass(componentsConfig.getRootControllerClass());}// 创建并将components对象置入resolvable dependencies,以便注入到需要的bean中WebxComponentsImpl components = new WebxComponentsImpl(componentsContext,componentsConfig.getDefaultComponent(), rootController, parentConfiguration);beanFactory.registerResolvableDependency(WebxComponents.class, components);// 初始化每个componentfor (String componentName : componentNames) {ComponentConfig componentConfig = specifiedComponents.get(componentName);String componentPath = null;WebxController controller = null;if (componentConfig != null) {componentPath = componentConfig.getPath();controller = componentConfig.getController();}if (controller == null) {controller = (WebxController) BeanUtils.instantiateClass(componentsConfig.getDefaultControllerClass());}// 每个WebxComponent就是一个子模块// 子模块的初始化WebxComponentImpl component = new WebxComponentImpl(components, componentName, componentPath,componentName.equals(componentsConfig.getDefaultComponent()), controller,getWebxConfigurationName());components.addComponent(component);prepareComponent(component, componentNamesAndLocations.get(componentName));}return components;}...
}

然后还有几个静态内部类:
1. WebxComponentsImpl(Root+子模块的集合)
2. RootComponentImpl(特殊的Component,公有共享)
3. WebxComponentImpl(子模块的Component,私有,每个子模块对应着特定的path模式)

到此,Spring初始化完成,Webx的子模块以及相关的实例也初始化完成

接下来看一下WebxFrameworkFilter的源码:

/*** 初始化spring容器的filter。** @author Michael Zhou*/
public class WebxFrameworkFilter extends FilterBean {private final Logger log = LoggerFactory.getLogger(getClass());private String           parentContextAttribute;private WebxComponents   components;private RequestURIFilter excludeFilter;private RequestURIFilter passthruFilter;private String           internalPathPrefix;.../** 初始化filter。 */@Overrideprotected final void init() throws Exception {WebApplicationContext parentContext = findParentContext();if (parentContext instanceof WebxComponentsContext) {components = ((WebxComponentsContext) parentContext).getWebxComponents();WebxConfiguration configuration = components.getParentWebxConfiguration();if (configuration != null) {internalPathPrefix = configuration.getInternalPathPrefix();internalPathPrefix = normalizeAbsolutePath(internalPathPrefix, true); // 规格化成/internal}}WebxRootController rootController = components.getWebxRootController();if (passthruFilter != null) {if (rootController instanceof PassThruSupportable) {((PassThruSupportable) rootController).setPassthruFilter(passthruFilter);} else {log.warn("You have specified Passthru Filter in /WEB-INF/web.xml.  "+ "It will not take effect because the implementation of WebxRootController ({}) does not support this feature.",rootController.getClass().getName());}}}// 过滤器过滤的逻辑@Overrideprotected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {String path = getResourcePath(request);...try {// root+subModule->RootController->Service// 上面提到的WebxRootController被实例化,在此产生了作用getWebxComponents().getWebxRootController().service(request, response, chain);} catch (...) {...}}
}

WebxRootControllerImpl 继承自 AbstractWebxRootController

/*** 对<code>WebxRootController</code>的默认实现。** @author Michael Zhou*/
public class WebxRootControllerImpl extends AbstractWebxRootController {@Overrideprotected boolean handleRequest(RequestContext requestContext) throws Exception {HttpServletRequest request = requestContext.getRequest();// Servlet mapping有两种匹配方式:前缀匹配和后缀匹配。// 对于前缀匹配,例如:/servlet/aaa/bbb,servlet path为/servlet,path info为/aaa/bbb// 对于前缀匹配,当mapping pattern为/*时,/aaa/bbb,servlet path为"",path info为/aaa/bbb// 对于后缀匹配,例如:/aaa/bbb.html,servlet path为/aaa/bbb.html,path info为null//// 对于前缀匹配,取其pathInfo;对于后缀匹配,取其servletPath。String path = ServletUtil.getResourcePath(request);// 再根据path查找component(子模块)WebxComponent component = getComponents().findMatchedComponent(path);boolean served = false;if (component != null) {try {WebxUtil.setCurrentComponent(request, component);// 获取handleRequest执行结果served = component.getWebxController().service(requestContext);} finally {WebxUtil.setCurrentComponent(request, null);}}return served;}
}

先到AbstractWebxRootController 看一下Service方法的实现:

    public final void service(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws Exception {RequestContext requestContext = null;try {requestContext = assertNotNull(getRequestContext(request, response), "could not get requestContext");// 如果请求已经结束,则不执行进一步的处理。例如,当requestContext已经被重定向了,则立即结束请求的处理。if (isRequestFinished(requestContext)) {return;}// 请求未结束,则继续处理...request = requestContext.getRequest();response = requestContext.getResponse();// 如果是一个内部请求,则执行内部请求if (handleInternalRequest(request, response)) {return;}// 如果不是内部的请求,并且没有被passthru,则执行handleRequestif (isRequestPassedThru(request) || !handleRequest(requestContext)) {// 如果请求被passthru,或者handleRequest返回false(即pipeline放弃请求),// 则调用filter chain,将控制交还给servlet engine。giveUpControl(requestContext, chain);}} catch (...) {...}}

查看子模块源码:

public class WebxControllerImpl extends AbstractWebxController {// 管道private Pipeline pipeline;@Overridepublic void onRefreshContext() throws BeansException {super.onRefreshContext();initPipeline();}private void initPipeline() {pipeline = getWebxConfiguration().getPipeline();...}public boolean service(RequestContext requestContext) throws Exception {PipelineInvocationHandle handle = pipeline.newInvocation();handle.invoke();// 假如pipeline被中断,则视作请求未被处理。filter将转入chain中继续处理请求。return !handle.isBroken();}
}

查看一下Pipeline的实现:

/*** 代表一组顺序执行的操作,好象液体流过一根管道一样。** @author Michael Zhou*/
public interface Pipeline {/** 特殊的label,用来中断整个pipeline的执行。 */String TOP_LABEL = "#TOP";/*** 取得pipeline的标签。* <p>* 这是一个可选的参数,用来方便break中断指定label的pipeline。* </p>*/String getLabel();/** 创建一次新的执行。 */PipelineInvocationHandle newInvocation();/** 创建一次新的执行,并将此次执行看作另一个执行的子过程。 */PipelineInvocationHandle newInvocation(PipelineContext parentContext);
}

Pipline实现:

/*** 对<code>Pipeline</code>的实现。** @author Michael Zhou*/
public class PipelineImpl extends AbstractService<Pipeline> implements Pipeline {// 管道里面的元素private Valve[] valves;private String  label;@Overrideprotected void init() {if (valves == null) {valves = new Valve[0];}for (int i = 0; i < valves.length; i++) {assertNotNull(valves[i], "valves[%d] == null", i);}}/** 实现<code>PipelineContext</code>。 */private final class PipelineContextImpl implements PipelineContext, PipelineInvocationHandle {// pipline上下文private final PipelineContext parentContext;private final int             level;private int executedIndex  = -1;private int executingIndex = -1;private boolean             broken;private Map<String, Object> attributes;// 执行下一个valuepublic void invokeNext() {assertInitialized();if (broken) {return;}try {// 横向的下标自增executingIndex++;...// 暂不清楚这个记录什么executedIndex++;if (executingIndex < valves.length) {Valve valve = valves[executingIndex];try {...// 执行valuevalve.invoke(this);} catch (...) {...} finally {...}...} else {...}} finally {// 横向的下标自减executingIndex--;}}...public void invoke() throws IllegalStateException {// 初始化下标,每次请求只初始化一次executingIndex = executedIndex = -1;invokeNext();}...}
}

引入官网描述的一张图:
这里写图片描述

/*** 代表pipeline中的一个“阀门”。* <p>* 如同真实世界里的水管中的阀门,它可以控制和改变液体的流向,<code>Valve</code> 也可以控制pipeline中后续valves的执行。* <code>Valve</code>可以决定是否继续执行后续的valves,或是中断整个pipeline的执行。* </p>** @author Michael Zhou*/
public interface Valve {void invoke(PipelineContext pipelineContext) throws Exception;
}

通过上面的pipline的相关结构,其实和配置文件反应出来的是一样的,这是个有序的执行结构,而且可以通过配置文件的配置,改变其执行的顺序:

    <services:pipeline xmlns="http://www.alibaba.com/schema/services/pipeline/valves"><!-- 初始化turbine rundata,并在pipelineContext中设置可能会用到的对象(如rundata、utils),以便valve取得。 --><prepareForTurbine /><!-- 设置日志系统的上下文,支持把当前请求的详情打印在日志中。 --><setLoggingContext /><!-- 分析URL,取得target。 --><analyzeURL homepage="homepage" /><!-- 检查csrf token,防止csrf攻击和重复提交。 --><checkCsrfToken /><loop><choose><when><!-- 执行带模板的screen,默认有layout。 --><pl-conditions:target-extension-condition extension="null, vm, jsp" /><performAction /><performTemplateScreen /><renderTemplate /></when><when><!-- 执行不带模板的screen,默认无layout。 --><pl-conditions:target-extension-condition extension="do" /><performAction /><performScreen /></when><otherwise><!-- 将控制交还给servlet engine。 --><exit /></otherwise></choose><!-- 假如rundata.setRedirectTarget()被设置,则循环,否则退出循环。 --><breakUnlessTargetRedirected /></loop></services:pipeline>

从配置文件,我们可以看到checkCsrfToken,那么它就是对应着一个Value,可以看看Value的实现:
这里写图片描述
直接找一个比较容易理解的Value,那就是performActionValue,执行访问Screen/Module/的类的execute方法:

/*** 执行action module,通常用来处理用户提交的表单。** @author Michael Zhou*/
public class PerformActionValve extends AbstractValve {@Autowiredprivate HttpServletRequest request;@Autowiredprivate ModuleLoaderService moduleLoaderService;public void invoke(PipelineContext pipelineContext) throws Exception {TurbineRunData rundata = getTurbineRunData(request);// 检查重定向标志,如果是重定向,则不需要将页面输出。if (!rundata.isRedirected()) {String action = rundata.getAction();// 如果找到action,则执行之。if (!StringUtil.isEmpty(action)) {String actionKey = "_action_" + action;// 防止重复执行同一个action。if (rundata.getRequest().getAttribute(actionKey) == null) {rundata.getRequest().setAttribute(actionKey, "executed");try {moduleLoaderService.getModule(ACTION_MODULE, action).execute();} catch (...) {...}}}}// 执行接下面的Value,对应着上面的配置文件就是performScreenValuepipelineContext.invokeNext();}...
}

看看module是什么:

/*** 代表一个模块。** @author Michael Zhou*/
public interface Module {/** 执行模块。 */void execute() throws Exception;
}

看看exeute的实现:

public abstract class AbstractModuleEventAdapter extends AbstractDataBindingAdapterimplements InitializingBean, ModuleEvent {private final Map<String, MethodInvoker> handlers;private final MethodInvoker              preHandler;private final MethodInvoker              postHandler;@Autowiredprivate HttpServletRequest request;.../** 执行一个module。 */public void execute() throws ModuleEventException, ModuleEventNotFoundException {executeAndReturn();}/** 执行一个module,并返回值。 */public Object executeAndReturn() throws ModuleEventException, ModuleEventNotFoundException {Object result = null;String event = getEventName(request);MethodInvoker handler = null;// 查找精确匹配的方法if (event != null) {handler = handlers.get(event);}// 查找fallback methodif (handler == null) {handler = handlers.get(null);}...// 执行preHandlerif (preHandler != null) {...try {preHandler.invoke(moduleObject, log);} catch (...) {...}}ModuleEventException exception = null;try {// 执行event handler...try {result = handler.invoke(moduleObject, log);} catch (Exception e) {// 捕获异常exception = new ModuleEventException("Failed to execute handler: " + handler, e);}} finally {// 执行postHandlerif (postHandler != null) {...try {postHandler.invoke(moduleObject, log);} catch (Exception e) {if (exception == null) {// 捕获异常exception = new ModuleEventException("Failed to execute post-handler: " + postHandler, e);}}}}if (exception != null) {// 抛出异常throw exception;}return result;}...
}

整个Webx MVC的初始化以及访问大体完成了,剩下就是原路返回数据进行相关处理。


http://chatgpt.dhexx.cn/article/2Y3PqIsF.shtml

相关文章

Webx学习

六月中就要去阿里巴巴实习了,部门使用的web框架是Webx,喜大普奔的发现Webx是开源的,所以认真学习一下。主要参考指导手册 Webx总体介绍 设计理念 这里有许多框架设计的真知灼见! 一个框架的好坏,往往并不是由他所实现的具体功能好坏所决定的,而是由其所使用的基础框架…

webx mysql_idea使用Maven启动maven项目、 webx框架项目

一、打开 二、点击号选择maven 三、 (1)、Working directory : 选择项目路径 (2)、Command line: clean jetty:run-war -Djetty.port8086 -Dautoconfig.charsetUTF-8 -Dmaven.test.skip (3)、VM Options: -server -XX:PermSize256M -XX:MaxPermSize512M (4)、点击Environment V…

webx mysql_Webx项目的获取与验证

在JavaWeb环境配置后就可进行Webx实例项目的获取与研读了。 1.创建一个初始的Demo工程。 1)下载 Webx Maven 项目的目录结构Artifact插件。 2) 创建WebxDemo项目 打开命令行工具(Windows cmd或Unix/Linux bash)&#xff0c;输入如下命令&#xff1a; mvn archetype:generate -D…

Webx框架

Webx是一个框架&#xff0c;它可用来做下面的事情&#xff1a; 创建一个全功能的Web应用 Webx提供了创建一个Web应用所需要的所有必要功能. 创建一个新的Web框架 Webx允许你定制、甚至重写大部分的Webx框架逻辑&#xff0c;从而实现全新的功能&#xff0c;或者和其它应用框…

Webx简介(转)

经常会到博客来看看大家的一些文章&#xff0c;都写的相当精彩&#xff0c;有水平&#xff0c;感觉大家好像都写了&#xff0c;自己没什么写的&#xff0c;后来跟师傅婉佩沟通&#xff0c;才了解到这样想是错的&#xff0c;每个人针对每个东西可能想法观点都不同&#xff0c;写…

WebX入门指南

[说明] 本文围绕WebX的Web框架展开&#xff0c;试图将整个开发中使用的软件栈或者说生态系统串联起来。本文中不讲解原理性的东西&#xff0c;只是讲解各种场景下如何使用WebX相关的技术。入门指南中涉及到的实践指南和原理指南&#xff0c;不会展开&#xff0c;在后续博文中&a…

WebX框架解析及使用教程

WebX框架是阿里巴巴集团开发的&#xff0c;它建立在SpringEx的基础上&#xff0c;具有超强的扩展能力。 一、Webx的层次结构&#xff08;从里到外&#xff09; &#xff08;1&#xff09;SpringExt&#xff1a;基于Spring&#xff0c;提供扩展组件的能力 &#xff08;2&#xf…

VSCode中Emmet使用

文章目录 HTML部分1. 添加类&#xff0c;id&#xff0c;文本和属性2. 嵌套和分组3. 隐式标签4. 定义多个元素* 和 编号$5. 添加虚拟文字6. 其它 CSS部分1. 属性和属性值的缩写2. 属性值的单位其它 HTML部分 1. 添加类&#xff0c;id&#xff0c;文本和属性 div.box#box > …

linux vim emmet,emmet-vim

最近啊&#xff0c;我投奔了网页的开发&#xff0c;看了一本《head first HTML and CSS》的书&#xff0c;感觉非常不错&#xff0c;然后又配置了一些vim里面用到的插件&#xff0c;现在我把学习到的东西记录下来&#xff01; 首先&#xff0c;我不会在这里写emmet 的具体操作方…

Emmet 语法

Emmet语法前身是Zen coding&#xff0c;来提高html和css的编写速度&#xff0c;vscode内部已经集成该语法了 1、快速生成html结构语法 生成标签&#xff1a; 直接输入标签名&#xff0c;再按TAB键&#xff0c;such as 你打个 div 再按tab&#xff0c;就会直接生成 (这里打不出…

emmet写法

1.写一个递增的img路径 img[srcimage/com/$$.png]*10 效果

6.Emmet 语法与快速格式化代码

Emmet语法可以让我们在写网页的时候速度更快&#xff0c;我当前写网页的工具是pycharm&#xff0c;在pycharm中使用Emmet&#xff0c;我们需要点击File,然后点击Setting 搜索emmet&#xff0c;保证这里是勾选状态 安装后如果不进行其他设置&#xff0c;emmet自动被勾选 目录 …

Emmet语法总结

1 Emmet简介 Emmet是一个Web开发工具&#xff0c;用于加快HTML和CSS代码的编写速度。使用Emmet能够通过简短的表达式生成HTML或CSS代码片段。另外&#xff0c;截至2022年&#xff0c;主流的编辑器工具如Visual Studio Code、WebStorm都已经集成了Emmet工具&#xff0c;无需手动…

Linux 配置全面讲解(安装JDK、Mysql、Nginx)

1 Linux概述 1.1 Linux介绍 Linux是一套免费使用和自由传播的类Unix操作系统&#xff0c;是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思…

【JAVA秒会技术之ConcurrentHashMap】JDK1.7与JDK1.8源码区别

前言 以前写过介绍HashMap的文章&#xff0c;文中提到过HashMap在put的时候&#xff0c;插入的元素超过了容量&#xff08;由负载因子决定&#xff09;的范围就会触发扩容操作&#xff0c;就是rehash&#xff0c;这个会重新将原数组的内容重新hash到新的扩容数组中&#xff0c;…

安装笔记--eclipse+jdk+neo4j安装与配置

1.eclipse安装2.JDK安装3.环境变量配置4.在eclipse中创建与导入项目4-1 eclipse导入项目 5.neo4j配置 1.eclipse安装 第一步&#xff1a;下载eclipse&#xff0c;并安装。 下载链接: http://www.eclipse.org/downloads/. 点击 Download Packages; 如图&#xff1a;根据自己的…

JDK7与JDK8中HashMap的实现

JDK7中的HashMap HashMap底层维护一个数组&#xff0c;数组中的每一项都是一个Entry transient Entry<K,V>[] table;我们向 HashMap 中所放置的对象实际上是存储在该数组当中&#xff1b; 而Map中的key&#xff0c;value则以Entry的形式存放在数组中 static class En…

VirtualBox虚拟机安装CentOS,安装jdk

CentOS 安装&#xff0c;安装jdk 1. CentOS 简介 CentOS 是一个基于Red Hat Linux 提供的可自由使用源代码的企业级Linux发行版本。每个版本的 CentOS都会获得十年的支持&#xff08;通过安全更新方式&#xff09;。新版本的 CentOS 大约每两年发行一次&#xff0c;而每个版本…

JDK1.7安装及校验

JDK的全称是JavaSE Development Kit&#xff0c;即java开发工具包&#xff0c;是sun公司提供的一套用于开发java应用程序的开发包&#xff0c;它提供了编译、运行java程序所需的各种工具和资源&#xff0c;包括java编译器、java运行时环境&#xff0c;以及常用的java类库等。 …

JVM调优(jdk8)与垃圾回收器详解

JVM调优与垃圾回收器详解 这张是jdk8的jvm模型&#xff1a; 黄色框的是线程共享区域、蓝色框的是线程私有(也就是每个线程单独一份) jvm模型从大的角度说有&#xff1a;类装载子系统、字节码执行引擎、运行时数据区。我这里主要讲运行时数据区。 一、JVM内存模型 1、名词解释…