热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:SpringBoot|第三十四章:CXF构建WebService服务

篇首语:本文由编程笔记#小编为大家整理,主要介绍了SpringBoot|第三十四章:CXF构建WebService服务相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了SpringBoot | 第三十四章:CXF构建WebService服务相关的知识,希望对你有一定的参考价值。



前言


上一章节,讲解了如何使用Spring-WS构建WebService服务。其实,创建WebService的方式有很多的,今天来看看如何使用apache cxf来构建及调用WebService服务。




  • 前言

  • 一点知识

    • 何为Apache-CXF

    • 关于JAX-WS规范

      • 常用注解介绍



  • SpringBoot整合CXF实例

    • 服务端构建

    • 客户端调用

      • 异常捕获


    • 自定义拦截器

      • 服务端拦截器

      • 客户端拦截器



  • 参考资料

  • 总结

  • 最后

  • 老生常谈


一点知识


何为Apache-CXF


Apache CXF是一个开源的Services框架,CXF帮助您利用Frontend编程 API 来构建和开发Services,像JAX-WSJAX-RS。这些Services可以支持多种协议,比如:SOAPXML/HTTPRESTful HTTP或者CORBA,并且可以在多种传输协议上运行,比如:HTTPJMS 或者JBICXF大大简化了 Services 的创建,同时它可以天然地和Spring进行无缝集成


以下是官网给出的介绍:https://github.com/apache/cxf

技术分享图片

最常用的是使用cxf开发web-service。本身是基于JAX-WS规范来实现的。当然,本身CXF也实现了JAX-RS规范来实现RESTFul Service


关于JAX-WS规范


JAX-WS全称:Java API for XML-Based Web ServicesJAX-WS是一种编程模型,它通过支持将基于注释的标准模型用于开发Web Service应用程序和客户机来简化应用程序开发。


JAX-WS是Java程序设计语言一个用来创建Web服务的API。



  • 在服务器端,用户只需要通过Java语言定义远程调用所需要实现的接口SEI(service endpoint interface),并提供相关的实现,通过调用JAX-WS的服务发布接口就可以将其发布为WebService接口。

  • 在客户端,用户可以通过JAX-WS的API创建一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。当然JAX-WS也提供了一组针对底层消息进行操作的API调用,你可以通过Dispatch直接使用SOAP消息或XML消息发送请求或者使用Provider处理SOAP或XML消息。


常用注解介绍


JAX-WS提供了一系列的注解,可以对WebService的接口规范化。以下介绍下最常用的几个注解。




  • @WebService:用于将Java类标记为实现Web Service或者将服务端点接口 (SEI) 标记为实现Web Service接口。
    其包含的属性有:

    • name:此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类的简单名称 + Service。(字符串)

    • targetNamespace:默认的值为 "http://包名/" ,可以通过此变量指定一个自定义的targetNamespace值。

    • serviceName:对外发布的服务名,指定Web Service的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)

    • endpointInterface:

    • portName:wsdl:portName的值。缺省值为WebService.name+Port

    • wsdlLocation:指定用于定义 Web Service 的 WSDL 文档的 Web 地址


  • @WebMethod:表示作为一项Web Service操作的方法。仅支持在使用@WebService注解的类上使用@WebMethod注解。

    • operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)

    • action:定义此操作的行为。对于 SOAP 绑定,此值将确定 SOAPAction 头的值。缺省值为 Java 方法的名称。(字符串)

    • exclude:指定是否从 Web Service 中排除某一方法。缺省值为 false。(布尔值)


  • @WebParam:用于定制从单个参数至Web Service消息部件和XML元素的映射。

其他注解,可以查看:WebService注解总结

为了有个直观感受,大家可以看看以下这个wsdl文件,对应以上各注解属性的值(加了前缀oKong)。

//@WebService 属性示例
@WebService(targetNamespace = ‘http://www.lqdev.cn/webservice‘ ,name = "oKongName", serviceName="oKongServiceName", portName = "oKongPortName",endpointInterface="cn.lqdev.learning.springboot.cxf.service.AuthorService")
//@webMethod @WebParam 常用属性示例
@WebMethod(operatiOnName="oKongOperationName",action="oKongAction")
String getAuthorName(@WebParam(name = "paramName") String name);

技术分享图片

标记的有点花,⊙﹏⊙‖∣。大家可以自己对照下。


SpringBoot整合CXF实例


接下来,我们以一个简单的示例来演示下,如何发布服务及如何进行服务调用。



服务端构建

创建一个工程:spring-boot-cxf-service.

0.引入CXF的POM文件


org.apache.cxf
cxf-spring-boot-starter-jaxws
3.2.5

1.创建实体,按JAX-WS规范,创建接口及其实现类。
AuthorDto.java

/**
* 作者信息实体
* @author oKong
*
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AuthorDto {
String name;

List hobby;

String birthday;

String description;

Sex sex;
}

Sex.java性别枚举类

/**
* 性别枚举类
* @author oKong
*
*/
public enum Sex {
MALE("male"),
FEMALE("female");

String value;

Sex(String value) {
this.value = value;
}

public String value() {
return value;
}
public static Sex fromValue(String v) {
for (Sex c : Sex.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}

AuthorService.java接口类

/**
* 创建服务接口
* @author oKong
*
*/
@WebService(targetNamespace = WsConst.NAMESPACE_URI ,name = "authorPortType")
public interface AuthorService {
/**
* 根据名称获取作者信息
* @author 作者:oKong
*/
@WebMethod(operatiOnName="getAuthorByName")
AuthorDto getAuthor(@WebParam(name = "authorName") String name);
/**
* 获取作者列表信息
* @author oKong
*/
@WebMethod
List getAuthorList();

/**
* 返回字符串测试
* @author oKong
*/
String getAuthorString(@WebParam(name = "authorName")String name);
}

AuthorServiceImpl.java接口实现类

@WebService(
targetNamespace = WsConst.NAMESPACE_URI, //wsdl命名空间
name = "authorPortType", //portType名称 客户端生成代码时 为接口名称
serviceName = "authorService", //服务name名称
portName = "authorPortName", //port名称
endpointInterface = "cn.lqdev.learning.springboot.cxf.service.AuthorService")//指定发布webservcie的接口类,此类也需要接入@WebService注解
public class AuthorServiceImpl implements AuthorService{
@Override
public AuthorDto getAuthor(String name) {
AuthorDto author = new AuthorDto();
author.setBirthday("1990-01-23");
author.setName("姓名:" + name);
author.setSex(Sex.MALE);
author.setHobby(Arrays.asList("电影","旅游"));
author.setDescription("描述:一枚趔趄的猿。现在时间:" + new Date().getTime());
return author;
}
@Override
public List getAuthorList() {
List resultList = new ArrayList<>();
AuthorDto author = new AuthorDto();
author.setBirthday("1990-01-23");
author.setName("姓名:oKong");
author.setSex(Sex.MALE);
author.setHobby(Arrays.asList("电影","旅游"));
author.setDescription("描述:一枚趔趄的猿。现在时间:" + new Date().getTime());
resultList.add(author);
resultList.add(author);
return resultList;
}
@Override
public String getAuthorString(String name) {
AuthorDto author = getAuthor(name);
return author.toString();
}
}

注意:相关注解可以查看章节:常用注解介绍

主要是接口实现类的@WebService对应属性值都要wsdl文件的映射关系。

@WebService(
targetNamespace = WsConst.NAMESPACE_URI, //wsdl命名空间
name = "authorPortType", //portType名称 客户端生成代码时 为接口名称
serviceName = "authorService", //服务name名称
portName = "authorPortName", //port名称
endpointInterface = "cn.lqdev.learning.springboot.cxf.service.AuthorService")//指定发布webservcie的接口类,此类也需要接入@WebService注解

2.创建常量类,配置类,设置访问uri路径等。

WsConst.java

/**
* 常量类
* @author oKong
*
*/
public class WsConst {
public static final String NAMESPACE_URI = "http://www.lqdev.cn/webservice";
}

CxfWebServiceConfig.java

/**
* cxf配置类
* @author oKong
*
*/
@Configuration
public class CxfWebServiceConfig {

//这里需要注意 由于springmvc 的核心类 为DispatcherServlet
//此处若不重命名此bean的话 原本的mvc就被覆盖了。可查看配置类:DispatcherServletAutoConfiguration
//一种方法是修改方法名称 或者指定bean名称
//这里需要注意 若beanName命名不是 cxfServletRegistration 时,会创建两个CXFServlet的。
//具体可查看下自动配置类:Declaration org.apache.cxf.spring.boot.autoconfigure.CxfAutoConfiguration
//也可以不设置此bean 直接通过配置项 cxf.path 来修改访问路径的
@Bean("cxfServletRegistration")
public ServletRegistrationBean dispatcherServlet() {
//注册servlet 拦截/ws 开头的请求 不设置 默认为:/services/*
return new ServletRegistrationBean(new CXFServlet(), "/ws/*");
}

/**
* 申明业务处理类 当然也可以直接 在实现类上标注 @Service
* @author oKong
*/
@Bean
public AuthorService authorService() {
return new AuthorServiceImpl();
}

/*
* 非必要项
*/
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus springBus = new SpringBus();
return springBus;
}

/*
* 发布endpoint
*/
@Bean
public Endpoint endpoint(AuthorService authorService) {
EndpointImpl endpoint = new EndpointImpl(springBus(), authorService);
endpoint.publish("/author");//发布地址
return endpoint;
}
}

注意事项:



  • 配置ServletRegistrationBean时,需要注意设置方法的名称或者bean的名称时,不要和默认的DispatcherServlet类重名了,会导致原先的mvc接口无法使用,因为被覆盖了。

  • 修改访问的路径可以通过设置ServletRegistrationBean来修改,但同时,要注意需要设置bean的名称为cxfServletRegistration,不然会造成注册多个CXFServlet的。具体原因可查看自动配置类:org.apache.cxf.spring.boot.autoconfigure.CxfAutoConfiguration

技术分享图片

所以,修改访问路径还可以通过配置项:cxf.path来设置。其默认的访问url为:/services

3.创建启动类,同时启动应用。

/**
* cxf服务发布示例
* @author oKong
*
*/
@SpringBootApplication
@Slf4j
public class CxfServiceApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(CxfServiceApplication.class, args);
log.info("spirng-boot-cxf-service-chapter34启动!");
}
}

启动后,可以从控制台看见可以访问的url路径信息。

2018-11-10 22:06:40.898 INFO 46364 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: ‘CXFServlet‘ to [/ws/*]
2018-11-10 22:06:40.899 INFO 46364 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: ‘dispatcherServlet‘ to [/]

访问:http://127.0.0.1:8080/ws/author?wsdl ,验证是否发布成功。

技术分享图片

自此,webService发布成功了。


客户端调用

创建一个客户端工程:spring-boot-cxf-client

0.引入cxf依赖。


org.apache.cxf
cxf-spring-boot-starter-jaxws
3.2.5

1.创建wsdl文件,同时利用插件:cxf-codegen-plugin创建相关类。



org.apache.cxf
cxf-codegen-plugin
3.2.5


generate-sources
generate-sources

${project.build.directory}/generated/cxf


src/main/resources/wsdl/author.wsdl
classpath:wsdl/author.wsdl




wsdl2java



wsdl文件,放入main/resources/wsdl目录下。之后执行:mvn generate-sources命令,就会自动创建相应的类文件了。拷贝相应的类文件至src/java目录下即可。或者直接指定sourceRoot也是可以的。

技术分享图片

2.创建调用的配置类,这里演示两种方式。

WsConst.java

/**
* 常量类
* @author oKong
*
*/
public class WsConst {
public static final String NAMESPACE_URI = "http://www.lqdev.cn/webservice";
public static final String SERVICE_ADDRESS= "http://127.0.0.1:8080/ws/author?wsdl";
}

CxfClinetConfig.java

/**
* 配置类
*
* @author oKong
*
*/
@Configuration
public class CxfClientConfig {

/**
* 以接口代理方式进行调用 AuthorPortType接口
*/
@Bean("cxfProxy")
public AuthorPortType createAuthorPortTypeProxy() {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setServiceClass(AuthorPortType.class);
jaxWsProxyFactoryBean.setAddress(WsConst.SERVICE_ADDRESS);//服务地址:http://127.0.0.1:8080/ws/autho
return (AuthorPortType) jaxWsProxyFactoryBean.create();
}

/*
* 采用动态工厂方式 不需要指定服务接口
*/
@Bean
public Client createDynamicClient() {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(WsConst.SERVICE_ADDRESS);
return client;
}
}

注意:除了使用JaxWsProxyFactoryBeanJaxWsDynamicClientFactory调用外,还可以直接使用自动生成的AuthorService类直接调用的,此类继承至javax.xml.ws.Service
如:

/*
* 直接调用
*/
@Bean("jdkProxy")
public AuthorPortType createJdkService() {
AuthorService authorService = new AuthorService();
return authorService.getAuthorPortName();
}

其实,最后都是使用AuthorPortType进行调用的。

3.创建控制层,进行调用示例。

/**
* 调用示例
* @author oKong
*
*/
@RestController
@RequestMapping("/cxf")
public class DemoController {
@Autowired
Client client;

@Autowired
@Qualifier("cxfProxy")
AuthorPortType authorPort;

@GetMapping("/getauthorstring")
public String getAuthorString(String authorName) {
return authorPort.getAuthorString(authorName);
}

@GetMapping("/getauthor")
public AuthorDto getAuthor(String authorName) {
return authorPort.getAuthorByName(authorName);
}

@GetMapping("/getauthorlist")
public List getAuthorList() {
return authorPort.getAuthorList();
}

@GetMapping("/dynamic/{operation}")
public Object getAuthorStringByDynamic(@PathVariable("operation")String operationName, String authorName) throws Exception {
//这里就简单的判断了
Object[] objects = null;
// client.getEndpoint().getBinding().getBindingInfo().getOperations()
if ("getAuthorList".equalsIgnoreCase(operationName)) {
objects = client.invoke(operationName);
} else if ("getAuthorString".equalsIgnoreCase(operationName)) {
objects = client.invoke(operationName, authorName);
} else if ("getAuthorByName".equalsIgnoreCase(operationName)) {
objects = client.invoke(operationName, authorName);
} else {
throw new RuntimeException("无效的调用方法");
}
return objects != null && objects.length > 0 ? objects[0] : "返回异常";
}
}

4.编写启动类,同时制定应用端口为:8090。

/**
* cxf-客户端调用示例
*
* @author oKong
*
*/
@SpringBootApplication
@Slf4j
public class CxfClientApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(CxfClientApplication.class, args);
log.info("spring-boot-cxf-client-chapter34启动!");
}
}

端口号配置:

server.port=8090

5.启动应用,依次访问。查看是否调用成功。

http://127.0.0.1:8090/cxf/getauthorstring?authorName=oKong

技术分享图片

http://127.0.0.1:8090/cxf//getauthorlist?authorName=oKong

技术分享图片

动态工厂方式调用:
http://127.0.0.1:8090/cxf/dynamic/getAuthorList?authorName=oKong
技术分享图片

其他的就不一一贴图了,可自行访问下。


异常捕获

Cxf发生异常时,会统一抛出:org.apache.cxf.interceptor.Fault类的,所以想要捕获异常,可以在统一异常里面进行捕获,关于统一异常处理,可以查看文章:第八章:统一异常、数据校验处理。


自定义拦截器

CXF的拦截器分为两种:InInterceptorOutInterceptor。显而易见,InInterceptor可以处理soap请求消息OutInterceptor可以处理soap响应消息。其拦截器都继承至AbstractPhaseInterceptor接口类,而且,本身也自带了很多的拦截器,可以自行添加看看,比如日志拦截器之类的:LoggingInInterceptorLoggingOutInterceptor

技术分享图片

请求流程图:

技术分享图片

拦截器链的阶段:

输入拦截器链有如下几个阶段,这些阶段按照在拦截器链中的先后顺序排列。

技术分享图片

输出拦截器链有如下几个阶段,这些阶段按照在拦截器链中的先后顺序排列。

技术分享图片

具体名称,可查看:org.apache.cxf.phase.Phase

技术分享图片

现在,我们自定义个实现拦截器,实现请求时header需要带上特定参数,或者大家可不写一些安全校验的自定义拦截器,本例只是简单的示例。


服务端拦截器

1.检验拦截器:CheckAuthInterceptor.java

/**
* 简易-安全校验拦截器
*
* @author oKong
*
*/
@Slf4j
public class CheckAuthInterceptor extends AbstractPhaseInterceptor {
public CheckAuthInterceptor() {
super(Phase.PRE_INVOKE);// 拦截节点:调用之前
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
log.info("检验拦截器开始检验:{}", message);
// 处理方法
List headers = message.getHeaders();
// 判断是否存header
// 检查headers是否存在
if (headers == null | headers.size() <1) {
throw new Fault(new IllegalArgumentException("验证失败,请传入正确参数(40001)"));//可自定义编码规范
}
//取出header
Header header = headers.get(0);
//获取对象
Element element = (Element) header.getObject();//这里获取的就时 auth对象了
NodeList tokenNode = element.getElementsByTagName("token");
if(tokenNode == null || tokenNode.getLength() <1) {
//无token节点
throw new Fault(new IllegalArgumentException("验证失败,请传入正确参数(40002)"));//自定义编码规范
}
//获取token
String token = tokenNode.item(0).getTextContent();
log.info("请求的token为:{}", token);
//这里可以对token 有效性进行判断
}
}

2.Endpoint中加入拦截器配置。

/*
* 发布endpoint
*/
@Bean
public Endpoint endpoint(AuthorService authorService) {
EndpointImpl endpoint = new EndpointImpl(springBus(), authorService);
endpoint.publish("/author");//发布地址
endpoint.getInInterceptors().add(createCheckAuthInterceptor());//加入拦截器
// endpoint.getOutInterceptors().add()//响应拦截器
return endpoint;
}

@Bean
public Interceptor createCheckAuthInterceptor(){
return new CheckAuthInterceptor();
}

客户端拦截器

1.编写拦截器。

/**
* 简易-安全校验拦截器
* @author oKong
*
*/
public class AuthInterceptor extends AbstractPhaseInterceptor{

public AuthInterceptor() {
super(Phase.PREPARE_SEND);//准备请求时进行拦截
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
//处理方法
List headers = message.getHeaders();

Document doc = DOMUtils.createDocument();
Element element = doc.createElement("auth");
Element tokenEle = doc.createElement("token");
tokenEle.setTextContent(UUID.randomUUID().toString());
element.appendChild(tokenEle);
//这里需要注意 默认情况下 是使用 org.w3c.dom.Element对象设置对象值的。
//也可以指定 DataBinding 设置对象的。可继承抽象类: org.apache.cxf.databinding.AbstractDataBinding
//具体源码可查看:org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor
Header tokenHeader = new SoapHeader(new QName(""), element);
// tokenHeader.setDataBinding()
headers.add(tokenHeader);
}
}

这里需要注意:



  • 设置header时,默认是org.w3c.dom.Element对象。

  • 自定义对象时,可设置DataBinding类来解析(未尝试,只是看了一眼源码,里面有此逻辑,有兴趣的同学可以自行试试)。

2.请求类中加入拦截器。
CxfClientConfig.java

/**
* 以接口代理方式进行调用 AuthorPortType接口
*/
@Bean("cxfProxy")
public AuthorPortType createAuthorPortTypeProxy() {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setServiceClass(AuthorPortType.class);
jaxWsProxyFactoryBean.setAddress(WsConst.SERVICE_ADDRESS);//服务地址:http://127.0.0.1:8080/ws/autho
jaxWsProxyFactoryBean.getOutInterceptors().add(createInterceptor());//加入自定义拦截器
return (AuthorPortType) jaxWsProxyFactoryBean.create();
}

/*
* 采用动态工厂方式 不需要指定服务接口
*/
@Bean
public Client createDynamicClient() {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(WsConst.SERVICE_ADDRESS);
client.getOutInterceptors().add(createInterceptor());
return client;
}

@Bean
public Interceptor createInterceptor() {
return new AuthInterceptor();
}

重新启动后,再次请求就可以看见相关日志输出了,可以试着不设置token,看看有拦截。

技术分享图片

异常请求:

技术分享图片


参考资料



  1. http://cxf.apache.org/docs/springboot.html


  2. https://www.code996.cn/post/2017/cxf-interceptor/


    总结


    本章节主要简单介绍了apache-cxf的使用。这文章示例写下来,我发现比spring-ws更简单呀,也更让人容易理解、逻辑比较清晰,而且也能设置一些差异化的东西。不知道是不是真的对spring-ws了解的不够呀,没有发现spring-ws的优点呀。自此,关于WebService的文章就暂时告一段落了。




最后


目前互联网上很多大佬都有SpringBoot系列教程,如有雷同,请多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有所错误之处,还望提出,谢谢。



老生常谈



  • 个人QQ:499452441

  • 微信公众号:lqdevOps

技术分享图片

个人博客:http://blog.lqdev.cn

完整示例:https://github.com/xie19900123/spring-boot-learning/tree/master/chapter-34









推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 业务:Payments&Risk大数据/AI/数据可视化时间要求:至少实习6个月,每周5天,入职时间4-5月 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 标题: ... [详细]
  • AssetbundlegenerateemptyJavaScriptandCSSfiles资产包生成空的JavaScript和CSS文件namespacefrontend\ass ... [详细]
  • 本文总结了Java中日期格式化的常用方法,并给出了示例代码。通过使用SimpleDateFormat类和jstl fmt标签库,可以实现日期的格式化和显示。在页面中添加相应的标签库引用后,可以使用不同的日期格式化样式来显示当前年份和月份。该文提供了详细的代码示例和说明。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
author-avatar
凯鹏2502896277
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有