Java WSDL 服務(wù)調(diào)用入門分享

Java WSDL 服務(wù)調(diào)用入門分享

第一次自己使用代碼直接調(diào)用webservice叽奥。對(duì)于這種網(wǎng)上很難找資料椅文,而且找到了不會(huì)用,會(huì)用但是會(huì)報(bào)錯(cuò)的代碼同衣。內(nèi)心是非常痛苦的。要靜下心來仔細(xì)學(xué)習(xí)webservice也是不可能的翩剪,因?yàn)榉浅Zs乳怎。所以就把我終于學(xué)會(huì)調(diào)用webservice的關(guān)鍵過程寫下

webservice說明

此為不專業(yè)的說明,僅做了解用前弯。且代碼都是從片段里面截取出來的,僅供思路參考秫逝,不能直接拿來用恕出。

webservice應(yīng)該就是想用于跨平臺(tái)的交互方式,因?yàn)樵谒鼜?fù)雜的xml里面违帆,規(guī)定了調(diào)用的方式浙巫,參數(shù)的對(duì)象(強(qiáng)類型)等等信息。而WSDL(Web Services Description Language)應(yīng)該就是一種針對(duì)webservice更加詳細(xì)的約定,因?yàn)閃SDL描述了webservice的函數(shù)的畴、參數(shù)渊抄、返回值等說明。

如何調(diào)用

  • 自己寫調(diào)用代碼丧裁,我不會(huì)护桦,只能祈禱大家以后對(duì)接能少遇到webservice
  • 使用CFX生成。下面我講一下如何使用cfx生成可以直接調(diào)用的代碼煎娇,以及如何調(diào)用二庵。

CFX生成可直接調(diào)用的代碼1

思路如下:下載插件 -> 根據(jù)給出的xml生成對(duì)應(yīng)的代碼 -> 在代碼里面找到main方法 -> 模仿main方法自己去調(diào)用 -> 封裝讓接口更加易用

  • 下載cfx的軟件。http://mirrors.tuna.tsinghua.edu.cn/apache/cxf/3.3.3/apache-cxf-3.3.3.zip

  • 解壓后缓呛,打開bin文件夾催享,找到我們需要運(yùn)行的 wsdl2java

  • 在bin文件夾,打開CMD哟绊。輸入命令:

    wsdl2java -p 這里填寫你的包名 -d 這里填寫你生成代碼的位置 -client -encoding utf-8 -noAddressBinding  這里填寫WSDL的地址
    

注意:使用git bash可能會(huì)有以下問題因妙,可嘗試使用自帶的CMD

image.png

你的包名:指的是接下來生成的文件會(huì)在XX.XX包下面。比如:我填寫的是com.google票髓,那么生成的文件結(jié)構(gòu)如此:package com.google.test;

代碼的位置:指的是生成的文件會(huì)在XXX路徑下面兰迫。比如:我填寫的是C:\Users\shihu\Documents\wsdl,那么生成的文件就會(huì)在C:\Users\shihu\Documents\wsdl文件下炬称。

WSDL的地址:指的是你將要調(diào)用的wsdl的地址汁果,一般就是返回一個(gè)xml文件。比如:我填寫http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl玲躯,那么就是根據(jù)該地址返回的xml文件去生成代碼据德。這里我挑選了亞馬遜的測(cè)試?yán)印?a target="_blank">這里有更多的例子,只需要將地址替換即可跷车。

所以棘利,完整的命令可以如下:

wsdl2java -p com.google -d C:\Users\shihu\Documents\wsdl -client -encoding utf-8 -noAddressBinding  http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl

生成以后的目錄結(jié)構(gòu)如下非常多文件,但是別怕下面會(huì)大致說明注1

C:.
└─com
    └─google
            Accessories.java  --dom實(shí)體
            Arguments.java    --dom實(shí)體
            AWSECommerceService.java  --webservice 的service
            AWSECommerceServicePortType.java --可以獲取webservice入口的
            AWSECommerceServicePortType_AWSECommerceServicePortCA_Client.java --入口
            AWSECommerceServicePortType_AWSECommerceServicePortCN_Client.java --入口
            AWSECommerceServicePortType_AWSECommerceServicePortDE_Client.java --入口
            AWSECommerceServicePortType_AWSECommerceServicePortES_Client.java --入口
            ...
  • 導(dǎo)入并運(yùn)行代碼

    面對(duì)這些陌生的代碼朽缴,我們?cè)撊绾沃稚泼担亢芎?jiǎn)單,找到入口(main方法)就可以密强。

    • main方法在**Endpoint_Client **結(jié)尾的文件里面茅郎;里面自動(dòng)生成了所有服務(wù)端提供的方法。我們只需要調(diào)用一下main方法就可以幫我們調(diào)試所有的接口了或渤。
    • 然后我們模仿main方法系冗,自己將service實(shí)例化出來,就可以直接調(diào)用服務(wù)端接口了薪鹦。

額外產(chǎn)物

將返回的數(shù)據(jù)轉(zhuǎn)化為json

返回之后的是一個(gè)dom數(shù)據(jù)掌敬,那么我們?nèi)绾伟阉D(zhuǎn)化為JSON對(duì)象呢惯豆?

返回的實(shí)體大致如下:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "username",
    "password"
})
@XmlRootElement(name = "login")
public class Login {
    @XmlElementRef(name = "username", namespace = "http://sys.ws.xxx.com", type = JAXBElement.class, required = false)
    protected JAXBElement<String> username;
    @XmlElementRef(name = "password", namespace = "http://sys.ws.xxx.com", type = JAXBElement.class, required = false)
    protected JAXBElement<String> password;
    ...

如果你和我情況類似,那么你可以使用以下方法轉(zhuǎn)化為JSON奔害。我封裝了2部分楷兽,一個(gè)是只轉(zhuǎn)化一個(gè),另外一個(gè)是轉(zhuǎn)化集合的华临。其實(shí)本質(zhì)都是一樣的芯杀。最主要的代碼是final String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(e);

/**
     * 轉(zhuǎn)化xml對(duì)象為json
     * @param tClass
     * @param value
     * @param <E>
     * @return
     */
public static <E extends Object> JSONObject convertToObject(Class<E> tClass, E value){
    List<E> list = new ArrayList<E>();
    list.add(value);
    final List<JSONObject> jsonObjects = convertToObject(tClass, list);
    return jsonObjects.isEmpty()?new JSONObject():jsonObjects.get(0);
}
/**
 * 批量轉(zhuǎn)化xml對(duì)象為json
 * @param tClass
 * @param list
 * @param <E>
 * @return
 */
public static <E extends Object> List<JSONObject> convertToObject(Class<E> tClass, List<E> list){
    List<JSONObject> result = new ArrayList<>();
    for(E e : list){
        try {
            final String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(e);
            result.add( JSONObject.parseObject(json));
        } catch (JsonProcessingException ex) {
            logger.error(marker,"解析xml對(duì)象錯(cuò)誤!",e);
        }
    }
    return result;
}

處理SOAP異常

只要服務(wù)端有異常:包含程序未捕獲的異常银舱、參數(shù)校驗(yàn)不通過等瘪匿,都會(huì)返回ServerSOAPFaultException異常,我們主要是處理ServerSOAPFaultException異常寻馏。

  • 思路:添加一個(gè)切面棋弥,然后統(tǒng)一捕獲ServerSOAPFaultException異常。目的:封裝一層诚欠,將ServerSOAPFaultException異常轉(zhuǎn)化為我們自己的業(yè)務(wù)異常顽染,將SOAP的異常前后綴除去,讓他人更容易明白轰绵。

  • 實(shí)現(xiàn):下面是切面中的around:

    @Around(value = "log()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
      Object result = null;
      String argsJson = "";
      try{
          Object[] arguments = proceedingJoinPoint.getArgs();//傳入的參數(shù)
          argsJson = JSON.toJSONString(arguments);
      }catch (Exception e){
      }
      final String methodName = proceedingJoinPoint.getSignature().getName();
      try {
          result = proceedingJoinPoint.proceed();
      } catch (ServerSOAPFaultException e) {
          String EXCEPTION_PREFIX = "Client received SOAP Fault from server: ";
          String EXCEPTION_SUFFIX = " Please see the server log to find more detail regarding exact cause of the failure.";
          final String message = e.getMessage().replaceFirst(EXCEPTION_PREFIX,"").replaceFirst(EXCEPTION_SUFFIX,"");
          logger.error("調(diào)用接口異常",e);
          throw new CommonException(message);
      } catch (Exception e) {
          logger.error("調(diào)用接口異常",e);
          throw e;
      }
      return result;
    }
    

如何添加頭部

有時(shí)候粉寞,我們需要在SOAP頭部(服務(wù)器端的XML說明)或者h(yuǎn)ttp頭部添加驗(yàn)證信息(僅僅是請(qǐng)求的http頭部)。那么如何做到呢左腔?

  • SOAP頭部的添加唧垦,參考網(wǎng)上的2。思路如下:
  1. 實(shí)現(xiàn)HandlerResolver 接口

  2. 實(shí)現(xiàn)SOAPHandler<SOAPMessageContext> 接口

  3. 重寫handleMessage方法。

  4. new 一個(gè)HandlerResolver,并將實(shí)現(xiàn)類放入service

  5. service獲取endpoint調(diào)用

  6. 代碼:

    
    /**
     * 實(shí)現(xiàn)SOAPHandler
     * @return
     */
    private class RequesterCredentials implements SOAPHandler<SOAPMessageContext> {
      private Map<String,String> headers;
    
      public RequesterCredentials(Map<String,String> headers) {
        super();
        this.headers = headers;
      }
      public Set<QName> getHeaders() {
        return null;
      }
    
      @Override
      public void close(MessageContext context) {
      }
    
      @Override
      public boolean handleFault(SOAPMessageContext context) {
        // TODO return true
        logger.error("ws錯(cuò)誤處理映挂。");
        return true;
      }
    
      // 處理請(qǐng)求上下文
      @Override
      public boolean handleMessage(SOAPMessageContext context) {
        try {
          Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    
          if (outboundProperty.booleanValue()) {
            SOAPMessage message = context.getMessage();
    
            SOAPHeader header = message.getSOAPHeader();
            if (header == null) {
                message.getSOAPPart().getEnvelope().addHeader();
                header = message.getSOAPHeader();
            }
            SOAPElement authenticationToken = header.addChildElement("auth", "", "");
            authenticationToken.addChildElement("user").addTextNode("user");
            authenticationToken.addChildElement("password").addTextNode("password");
            authenticationToken.addChildElement("token").addTextNode("token");
          }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
      }
    }
    
    
    /**
     * 實(shí)現(xiàn)SOAPHandler
     * @return
     */
    public class HeaderHandlerResolver implements HandlerResolver {
      private RequesterCredentials requesterCredentials;
    
      public HeaderHandlerResolver(RequesterCredentials requesterCredentials){
          this.requesterCredentials=requesterCredentials;
      }
      @Override
      public List getHandlerChain(PortInfo portInfo) {
          return Arrays.asList(requesterCredentials);
      }
    }
    
    /**
     * 放入SOAPHandler,并調(diào)用
     * @return
     */
    RequesterCredentials  r=new RequesterCredentials (headers);
    HeaderHandlerResolver  headerHandlerResolver=new HeaderHandlerResolver (r);
    mathService.setHandlerResolver(headerHandlerResolver);
    Deposit1ServicePortType port = mathService.getDeposit1ServiceHttpSoap11Endpoint();
    
  • 添加http的頭部

    和上方的soap差不多坊秸。主要就是實(shí)現(xiàn)HandlerResolver,重寫handleMessage澎怒,修改請(qǐng)求的上下文褒搔。

    • 唯一的區(qū)別就是重寫的handleMessage不同

      /**
       * 實(shí)現(xiàn)SOAPHandler,一個(gè)headers成員變量,到時(shí)候放入header喷面。
       * @return
       */
      private class RequesterCredentials implements SOAPHandler<SOAPMessageContext> {
        private Map<String,String> ;
          ...
              
      // 改變一
      @Override
      public boolean handleMessage(SOAPMessageContext context) {
        Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outboundProperty.booleanValue()) {
          Map<String, List<String>> requestHeaders = new HashMap<>();
          for(String key:headers.keySet()){
              requestHeaders.put(key, Arrays.asList(headers.get(key)));
          }
          context.put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
        }
        return true;
      }
          
      
      /**
         * 放入SOAPHandler星瘾,并調(diào)用
         * @return
         */
      RequesterCredentials  r=new RequesterCredentials (headers);
      HeaderHandlerResolver  headerHandlerResolver=new HeaderHandlerResolver (r);
      mathService.setHandlerResolver(headerHandlerResolver);
      Deposit1ServicePortType port = mathService.getDeposit1ServiceHttpSoap11Endpoint();
      
  • 需要注意的是,添加的header是 Map<String, List<String>>乖酬,千萬不要手快死相,寫成 了Map<String, Object>,網(wǎng)上很多都是這里被坑了咬像。注意value是一個(gè)String的list。

將java對(duì)象轉(zhuǎn)化為dom對(duì)象工具

當(dāng)我們調(diào)用webservice方法的時(shí)候,傳入的參數(shù)并不是普通的java對(duì)象县昂,而是dom對(duì)象肮柜,那么我們?nèi)绾螌ava對(duì)象轉(zhuǎn)化為dom對(duì)象呢?

  • 非常需要的注意的大前提:DOM對(duì)象的Object屬性需要通過ObjectFactory統(tǒng)一create出來倒彰。

  • 我們這里借助了hutool的反射工具

    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>4.6.8</version>
    </dependency>
    
  • 思路:我們可以通過觀察dom對(duì)象結(jié)構(gòu) =》將java對(duì)象對(duì)應(yīng)的屬性轉(zhuǎn)化為dom對(duì)象需要的屬性=》把轉(zhuǎn)化好的屬性set進(jìn)dom對(duì)象

下面我們觀察一下CXF 生成的dom對(duì)象的Object屬性和普通屬性get审洞、set方法:

/**
 * 設(shè)置username屬性的值。
 *
 * @param value
 *     allowed object is
 *     {@link JAXBElement }{@code <}{@link String }{@code >}
 *
 */
public void setUsername(JAXBElement<String> value) {
    this.username = value;
}
...
/**
 * 設(shè)置money屬性的值待讳。
 *
 * @param value
 *     allowed object is
 *     {@link Double }
 *
 */
public void setMoney(Double value) {
    this.money = value;
}    

為什么要把Object類和java基類分開芒澜,因?yàn)橹挥蠴bject的子類(像String)才不是普通的set方法,而基類是普通的set方法创淡。

可以看到是一個(gè)JAXBElement包裝了一個(gè)普通的java類痴晦,所有在java類和dom類的類型保持一致的情況下(比如java是String,那么dom也是String)琳彩,我們可以通過反射誊酌,將對(duì)應(yīng)的屬性通過get方法,獲取到j(luò)ava對(duì)象原本的值露乏,然后再通過dom的ObjectFactoryt的create方法碧浊,組合成dom需要的類型的值,將轉(zhuǎn)化之后的屬性放入dom對(duì)象中瘟仿。

代碼如下:

/**
 * 可以轉(zhuǎn)化普通java的屬性為dom的屬性
 * @param objecrFactory 對(duì)象工廠實(shí)例
 * @param klass soap的類
 * @param property 對(duì)應(yīng)java類的屬性名(soap和java的屬性名字和類型需要保持一致)
 * @param value 需要設(shè)置的值
 * @param <T> 對(duì)象工廠類
 * @param <E> soap的類
 * @param <V> 屬性的類
 * @return
 */
public static <T,E,V> JAXBElement<V>  invokeSOAP(T objecrFactory, Class<E> klass, String property , V value){
    try{
        final String methodName = String.format("create%s%s", klass.getSimpleName(),
                property.substring(0, 1).toUpperCase() + property.substring(1));
        return ReflectUtil.invoke(objecrFactory,methodName,value);
    }catch (Exception e){
        logger.error("設(shè)置屬性失斚淙瘛!",e);
        return null;
    }
}

/**
 * 將一個(gè)普通java對(duì)象轉(zhuǎn)化為dom對(duì)象
 * @param entity java對(duì)象
 * @param objecrFactory 創(chuàng)建的dom工廠
 * @param soapClass soap對(duì)應(yīng)的對(duì)象class
 * @param <T> 實(shí)體的類
 * @param <O> dom對(duì)象工廠的類
 * @param <E> soap的類
 */
public static <T,O,E> E convertToSOAP(T entity,O objecrFactory, Class<E> soapClass){
 final E soapInstance = ReflectUtil.newInstance(soapClass);
   try{
    final Class<?> entityClass = entity.getClass();
      final Set<String> methodNames = ReflectUtil.getPublicMethodNames(entityClass);
        for(String methodName: methodNames){
          if(methodName.startsWith("get") && !objectMethods.contains(methodName) && ReflectUtil.getMethodByNameIgnoreCase(soapClass, methodName)!=null){//如果是get方法
            final String property = methodName.substring(3, methodName.length());
            Object value = ReflectUtil.invoke(entity, methodName);
            if(value instanceof BigDecimal){//BigDecimal需要轉(zhuǎn)化為double劳较,并且直接設(shè)置屬性
              value = ((BigDecimal) value).doubleValue();
              ReflectUtil.invoke(soapInstance,"set"+property,value);
              continue;
            }
            if(value!=null){
              ReflectUtil.invoke(soapInstance,"set"+property,invokeSOAP(objecrFactory, soapClass, property, value));
            }
          }
        }
        return soapInstance;
    }catch (Exception e){
        logger.error("批量設(shè)置屬性失斁灾埂!",e);
        return soapInstance;
    }
}

如何在postman中調(diào)試

拿到對(duì)方接口的第一時(shí)間兴想,就是想使用postman進(jìn)行測(cè)試幢哨。但是,webservice如何使用postman進(jìn)行測(cè)試呢嫂便?

  • 物料:谷歌瀏覽器捞镰、postman、wizdler插件毙替、以及一個(gè)wsdl網(wǎng)址

  • 我們這里可以借助一個(gè)谷歌插件對(duì)請(qǐng)求參數(shù)進(jìn)行生成:Wizdler

插件.jpg
  • 安裝插件之后岸售,在谷歌瀏覽器打開你可以需要調(diào)試的wsdl的網(wǎng)址。那么插件就會(huì)顯示出該wsdl對(duì)應(yīng)的方法厂画,如下圖:

    然后點(diǎn)擊需要調(diào)試的方法就可以生成請(qǐng)求體凸丸,其實(shí)簡(jiǎn)單的請(qǐng)求,可以直接通過該插件調(diào)試了

WSDL.jpg
請(qǐng)求體.png

修改請(qǐng)求體之后,我們可以直接通過頁面對(duì)方法進(jìn)行調(diào)用腻惠。點(diǎn)擊GO按鈕就可以直接發(fā)起請(qǐng)求了环肘。對(duì)應(yīng)的響應(yīng)如下:

插件發(fā)起的請(qǐng)求.png

同時(shí),我們可以將請(qǐng)求體復(fù)制到postman集灌,然后設(shè)置對(duì)應(yīng)的Content-Type悔雹,以及請(qǐng)求方法,使用post請(qǐng)求就可以在postman發(fā)起webservice請(qǐng)求了欣喧。以這里例子為例腌零,需要POST請(qǐng)求;body是xml格式唆阿;Content-Typeapplication/soap+xml; charset="UTF-8"益涧;就可以發(fā)送請(qǐng)求了。

post請(qǐng)求.png

webservice 網(wǎng)絡(luò)斷開后處理

webservice有一個(gè)奇葩的問題酷鸦。如果對(duì)方的webservice服務(wù)端是離線的狀態(tài)(服務(wù)器重啟/關(guān)閉導(dǎo)致我們無法獲取到WSDL的xml文件)饰躲,或?qū)е挛覀兛蛻舳?“啟動(dòng)的時(shí)候” 無法初始化webservice的一些東西,或者當(dāng)我們客戶端運(yùn)行的時(shí)候臼隔,服務(wù)端重啟了嘹裂,服務(wù)端重啟完畢之后,webservice的一些實(shí)例會(huì)變成null摔握,這就導(dǎo)致了我們無法正常使用webservice了寄狼。我是如何解決這個(gè)問題的呢?

  • 為什么要這樣處理氨淌?因?yàn)槲以?strong>類初始化的時(shí)候泊愧,將webservice的service和port全部初始化了,并放入靜態(tài)變量中盛正,這樣效率就高删咱,因?yàn)椴恍枰看味糿ew一次。所以豪筝,痰滋,事先初始化了webservice相關(guān)的,如果網(wǎng)絡(luò)斷開了续崖,那么就會(huì)拋出NPE異常了敲街。

    初始化代碼大致如下:

    @Service
    public class WsService{
        public static LoginService loginService;
        public static LoginServicePortType portType;
        public WsService(){
            loginService = new (new URL("url"), LOGIN_SERVICE_NAME);
            portType = loginService.getLoginServiceHttpSoap11Endpoint();
        }
        ...
    }
    
  • 思路:加入切面 =》代理webservice的每一個(gè)方法 =》每次進(jìn)入方法前,檢測(cè)ws相關(guān)的類是否為空 =》空則重新初始化

    把原來初始化的代碼封裝成一個(gè)statis方法:

    @Service
    public class WsService{
        public static LoginService loginService;
        public static LoginServicePortType portType;
        public WsService(){}
        public static initService(){
            try{//如果啟動(dòng)應(yīng)用的時(shí)候严望,恰好服務(wù)端無法使用多艇,那么會(huì)拋出異常,所以需要處理像吻。
                //不能把異常拋出峻黍,因?yàn)閽伋霎惓?huì)導(dǎo)致應(yīng)用無法啟動(dòng)复隆。為了保證應(yīng)用能正常啟動(dòng),必須處理異常
                //每次進(jìn)入方法的時(shí)候再檢查ws對(duì)象奸披,這樣就不影響應(yīng)用正常啟動(dòng)了昏名,等服務(wù)端正常了涮雷,就會(huì)自動(dòng)初始化了
                if(loginService == null){
                    loginService = new (new URL("url"), LOGIN_SERVICE_NAME);
                }
                if(portType == null){
                    portType = loginService.getLoginServiceHttpSoap11Endpoint();
                }            
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    

切面類:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 接口日志
 * @author shihu
 */
@Aspect
@Component
public class WsAspect {

    private Logger logger = LoggerFactory.getLogger(WsAspect.class);
    @Pointcut("execution(public * com.google.ws.WsService.*(..))")
    public void cut(){}
    @Before("cut()")
    public void doBefore(JoinPoint joinPoint){
        WsAspect.initService();// 確保每次進(jìn)入都驗(yàn)證是否為空
    }
}

總結(jié)

因?yàn)椴皇煜ebservice阵面,所以一開始完全就是一頭霧水。但是洪鸭,當(dāng)CFX自動(dòng)生成了代碼能直接調(diào)用之后样刷,整個(gè)流程就通了,豁然開朗览爵。但是置鼻,之后又為設(shè)置header頭痛。因?yàn)椴皇煜を阎瘢酝耆恢纇eader還區(qū)分soap的header和普通的http的header箕母。而前者,我花了大量的時(shí)間去研究俱济,最終都沒研究出來(因?yàn)榉?wù)端壓根就沒有嘶是,所以以后要問清楚,但是完全不懂ws所以也就不存在清不清楚的問題了)蛛碌,最終才得知是設(shè)置http的header聂喇,這個(gè)就簡(jiǎn)單了,就是處理請(qǐng)求的上下文蔚携,在上下文添加header就可以了希太。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酝蜒,隨后出現(xiàn)的幾起案子誊辉,更是在濱河造成了極大的恐慌,老刑警劉巖亡脑,帶你破解...
    沈念sama閱讀 211,496評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堕澄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡远豺,警方通過查閱死者的電腦和手機(jī)奈偏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躯护,“玉大人惊来,你說我怎么就攤上這事」字停” “怎么了裁蚁?”我有些...
    開封第一講書人閱讀 157,091評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵矢渊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我枉证,道長(zhǎng)矮男,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,458評(píng)論 1 283
  • 正文 為了忘掉前任室谚,我火速辦了婚禮毡鉴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秒赤。我一直安慰自己猪瞬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,542評(píng)論 6 385
  • 文/花漫 我一把揭開白布入篮。 她就那樣靜靜地躺著陈瘦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪潮售。 梳的紋絲不亂的頭發(fā)上痊项,一...
    開封第一講書人閱讀 49,802評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音酥诽,去河邊找鬼鞍泉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盆均,可吹牛的內(nèi)容都是我干的塞弊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,945評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼泪姨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼游沿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起肮砾,我...
    開封第一講書人閱讀 37,709評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤诀黍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后仗处,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眯勾,經(jīng)...
    沈念sama閱讀 44,158評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,502評(píng)論 2 327
  • 正文 我和宋清朗相戀三年婆誓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吃环。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,637評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洋幻,死狀恐怖郁轻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤好唯,帶...
    沈念sama閱讀 34,300評(píng)論 4 329
  • 正文 年R本政府宣布竭沫,位于F島的核電站,受9級(jí)特大地震影響骑篙,放射性物質(zhì)發(fā)生泄漏蜕提。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,911評(píng)論 3 313
  • 文/蒙蒙 一靶端、第九天 我趴在偏房一處隱蔽的房頂上張望谎势。 院中可真熱鬧,春花似錦躲查、人聲如沸它浅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,744評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鄙麦,卻和暖如春典唇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胯府。 一陣腳步聲響...
    開封第一講書人閱讀 31,982評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工介衔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骂因。 一個(gè)月前我還...
    沈念sama閱讀 46,344評(píng)論 2 360
  • 正文 我出身青樓炎咖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親寒波。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乘盼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,500評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,805評(píng)論 0 11
  • 一、Java基礎(chǔ) 1.寫出下面代碼的執(zhí)行結(jié)果 2.寫出下面代碼的執(zhí)行結(jié)果 3.寫出下面代碼的執(zhí)行結(jié)果 (此題需寫出...
    joshul閱讀 511評(píng)論 0 1
  • WebService介紹 首先我們來談一下為什么需要學(xué)習(xí)webService這樣的一個(gè)技術(shù)吧.... 問題一 如果...
    Java3y閱讀 9,561評(píng)論 5 139
  • JAVA面試題 1俄烁、作用域public,private,protected,以及不寫時(shí)的區(qū)別答:區(qū)別如下:作用域 ...
    JA尐白閱讀 1,146評(píng)論 1 0
  • 小編費(fèi)力收集:給你想要的面試集合 1.C++或Java中的異常處理機(jī)制的簡(jiǎn)單原理和應(yīng)用绸栅。 當(dāng)JAVA程序違反了JA...
    八爺君閱讀 4,578評(píng)論 1 114