blogjava-凯发k8网页登录

blogjava-凯发k8网页登录http://www.blogjava.net/paulwong/category/38240.htmlzh-cnwed, 19 oct 2022 02:41:07 gmtwed, 19 oct 2022 02:41:07 gmt60mongodb spring distincthttp://www.blogjava.net/paulwong/archive/2022/10/18/450835.htmlpaulwongpaulwongtue, 18 oct 2022 02:22:00 gmthttp://www.blogjava.net/paulwong/archive/2022/10/18/450835.htmlhttp://www.blogjava.net/paulwong/comments/450835.htmlhttp://www.blogjava.net/paulwong/archive/2022/10/18/450835.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/450835.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/450835.html
    private boolean needreordercheck(string requestid) {
        boolean result = false;
//        try(mongocursor mongocursor = 
//                mongotemplate.getcollection(mongotemplate.getcollectionname(accountnumproductlineindex.class))
//                             .distinct(key, filters.eq(request_id, requestid), string.class)
//                             .iterator()
//                )
        try(mongocursor mongocursor = 
                mongotemplate.getcollection(mongotemplate.getcollectionname(accountnumproductlineindex.class))
                             .aggregate(
                                 arrays.aslist(
                                    aggregates.project(
                                                    projections.fields(
                                                                    projections.excludeid(),
                                                                   projections.include(key),
                                                                   projections.include(request_id)
                                                                )
                                               ),
                                    aggregates.match(filters.eq(request_id, requestid)),
                                    aggregates.group("$"   key)
                                 )
                              )
                             .allowdiskuse(true)
                             .iterator();
        )
        {
            string key = null;
            boolean breakme = false;
            logger.info("needreordercheck.key --> start");
            while(mongocursor.hasnext()) {
                if(breakme) {
                    mongocursor.close();
                    break;
                }
                document keydocument = mongocursor.next();
                key = keydocument.getstring("_id");
//                key = mongocursor.next().getstring(key);
//                logger.info("needreordercheck.keydocument --> {}, key --> {}", keydocument, key);
                try(mongocursor indexmongocursor = 
                        mongotemplate.getcollection(accountnumproductlineindex.collection_name)
                                        .find(filters.and(filters.eq(request_id, requestid), filters.eq(key, key)))
                                        .iterator()
                )
                {
                    int preindex = -1, currentindex = -1;
                    document preindexdocument = null, currentindexdocument;
                    while(indexmongocursor.hasnext()) {
                        currentindexdocument = indexmongocursor.next();
//                        system.out.println(currentindexdocument.tojson());
                        if(preindexdocument != null) {
                             currentindex = currentindexdocument.getinteger(index);
                             preindex = preindexdocument.getinteger(index);
                             if(currentindex - preindex > 1) {
                                indexmongocursor.close();
                                breakme = true;
                                result = true;
                                break;
                            }
                        }
                        preindexdocument = currentindexdocument;
                    }
                }
            }
        }
        
        return result;
    }



paulwong 2022-10-18 10:22 发表评论
]]>
downloading large files using spring webclienthttp://www.blogjava.net/paulwong/archive/2022/09/22/450822.htmlpaulwongpaulwongthu, 22 sep 2022 05:14:00 gmthttp://www.blogjava.net/paulwong/archive/2022/09/22/450822.htmlhttp://www.blogjava.net/paulwong/comments/450822.htmlhttp://www.blogjava.net/paulwong/archive/2022/09/22/450822.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/450822.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/450822.htmlhttps://www.amitph.com/spring-webclient-large-file-download/



import lombok.requiredargsconstructor;
import org.springframework.core.io.buffer.databuffer;
import org.springframework.core.io.buffer.databufferutils;
import org.springframework.stereotype.service;
import org.springframework.web.reactive.function.client.webclient;
import reactor.core.publisher.flux;
import reactor.core.publisher.mono;

import java.io.ioexception;
import java.nio.file.files;
import java.nio.file.path;
import java.nio.file.standardopenoption;
import java.util.objects;

@service
@requiredargsconstructor
public class filedownloaderwebclientservice {
    private final webclient webclient;

    /**
     * reads the complete file in-memory. thus, only useful for very large file
     
*/
    public void downloadusingbytearray(path destination) throws ioexception {
        mono<byte[]> monocontents = webclient
                .get()
                .uri("/largefiles/1")
                .retrieve()
                .bodytomono(byte[].class);

        files.write(destination, objects.requirenonnull(monocontents.share().block()),
                standardopenoption.create);
    }

    /**
     * reading file using mono will try to fit the entire file into the databuffer.
     * results in exception when the file is larger than the databuffer capacity.
     
*/
    public void downloadusingmono(path destination) {
        mono databuffer = webclient
                .get()
                .uri("/largefiles/1")
                .retrieve()
                .bodytomono(databuffer.class);

        databufferutils.write(databuffer, destination,
                standardopenoption.create)
                .share().block();
    }

    /**
     * having using flux we can download files of any size safely.
     * optionally, we can configure databuffer capacity for better memory utilization.
     
*/
    public void downloadusingflux(path destination) {
        flux databuffer = webclient
                .get()
                .uri("/largefiles/1")
                .retrieve()
                .bodytoflux(databuffer.class);

        databufferutils.write(databuffer, destination,
                standardopenoption.create)
                .share().block();
    }
}


paulwong 2022-09-22 13:14 发表评论
]]>
spring integration - enrichhttp://www.blogjava.net/paulwong/archive/2021/09/21/435976.htmlpaulwongpaulwongtue, 21 sep 2021 05:40:00 gmthttp://www.blogjava.net/paulwong/archive/2021/09/21/435976.htmlhttp://www.blogjava.net/paulwong/comments/435976.htmlhttp://www.blogjava.net/paulwong/archive/2021/09/21/435976.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435976.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435976.html
package org.springframework.integration.stackoverflow.enricher;

import java.util.list;
import java.util.map;
import java.util.function.function;
import java.util.stream.collectors;

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.context.annotation.bean;
import org.springframework.http.httpmethod;
import org.springframework.integration.dsl.integrationflow;
import org.springframework.integration.dsl.integrationflows;
import org.springframework.integration.dsl.transformers;
import org.springframework.integration.http.dsl.http;
import org.springframework.web.client.resttemplate;

@springbootapplication
public class springintegrationenricherapplication {

    public static void main(string[] args) {
        springapplication.run(springintegrationenricherapplication.class, args);
    }

    @bean
    public integrationflow jsonenricherflow(resttemplate resttemplate) {
        return integrationflows.from(function.class)
                .transform(transformers.fromjson(map.class))
                .enrich((enricher) -> enricher
                        .>requestpayload((message) ->
                                ((list) message.getpayload().get("attributeids"))
                                        .stream()
                                        .map(object::tostring)
                                        .collect(collectors.joining(",")))
                        .requestsubflow((subflow) ->
                                subflow.handle(
                                        http.outboundgateway("/attributes?id={ids}", resttemplate)
                                                .httpmethod(httpmethod.get)
                                                .expectedresponsetype(map.class)
                                                .urivariable("ids", "payload")))
                        .propertyexpression("attributes", "payload.attributes"))
                ., map>transform(
                        (payload) -> {
                            payload.remove("attributeids");
                            return payload;
                        })
                .transform(transformers.tojson())
                .get();
    }

}







paulwong 2021-09-21 13:40
]]>
srping自带的事件监听机制http://www.blogjava.net/paulwong/archive/2021/04/09/435851.htmlpaulwongpaulwongfri, 09 apr 2021 06:55:00 gmthttp://www.blogjava.net/paulwong/archive/2021/04/09/435851.htmlhttp://www.blogjava.net/paulwong/comments/435851.htmlhttp://www.blogjava.net/paulwong/archive/2021/04/09/435851.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435851.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435851.html
import lombok.getter;
import org.springframework.context.applicationevent;


@getter
public class javastackevent extends applicationevent {

    /**
     * create a new {
@code applicationevent}.
     *
     * 
@param source the object on which the event initially occurred or with
     *               which the event is associated (never {
@code null})
     
*/
    public javastackevent(object source) {
        super(source);
    }


}

定义一个此事件观察者,即感兴趣者:
import lombok.nonnull;
import lombok.requiredargsconstructor;
import org.springframework.context.applicationlistener;
import org.springframework.scheduling.annotation.async;

/**
 * 观察者:读者粉丝
 
*/
@requiredargsconstructor
public class readerlistener implements applicationlistener {

    @nonnull
    private string name;

    private string article;

    @async
    @override
    public void onapplicationevent(javastackevent event) {
        // 更新文章
        updatearticle(event);
    }

    private void updatearticle(javastackevent event) {
        this.article = (string) event.getsource();
        system.out.printf("我是读者:%s,文章已更新为:%s\n", this.name, this.article);
    }

}

注册感兴趣者(将自身注入spring容器则完成注册),并制定发布机制(通过context发布事件):
import lombok.extern.slf4j.slf4j;
import org.springframework.boot.commandlinerunner;
import org.springframework.context.applicationcontext;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;

@slf4j
@configuration
public class observerconfiguration {

    @bean
    public commandlinerunner commandlinerunner(applicationcontext context) {
        return (args) -> {
            log.info("发布事件:什么是观察者模式?");
            context.publishevent(new javastackevent("什么是观察者模式?"));
        };
    }

    @bean
    public readerlistener readerlistener1(){
        return new readerlistener("小明");
    }

    @bean
    public readerlistener readerlistener2(){
        return new readerlistener("小张");
    }

    @bean
    public readerlistener readerlistener3(){
        return new readerlistener("小爱");
    }

}


paulwong 2021-04-09 14:55
]]>
csv 文件打开乱码,有哪些方法可以解决?http://www.blogjava.net/paulwong/archive/2021/03/23/435832.htmlpaulwongpaulwongtue, 23 mar 2021 02:30:00 gmthttp://www.blogjava.net/paulwong/archive/2021/03/23/435832.htmlhttp://www.blogjava.net/paulwong/comments/435832.htmlhttp://www.blogjava.net/paulwong/archive/2021/03/23/435832.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435832.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435832.html
掌握了这点相信乱码已经无法阻挡我们前进的步伐了:只需将不带 bom 头编码的 csv 文件,用文本编辑器(工具随意,推荐 notepad )打开并转换为带 bom 的编码形式(具体编码方式随意),问题解决。

当然,如果你是像我一样的码农哥哥,在生成 csv 文件的时候写入 bom 头更直接点,用户会感谢你的。

附录:对于 utf-8 编码,unicode 标准中是没有 bom 定义的,微软在自己的 utf-8 格式的文本文件之前加上了ef bb bf三个字节作为识别此编码的 bom 头,这也解释了为啥大部分乱码都是 utf-8 编码导致的原因

spring batch中生成csv文件时的凯发天生赢家一触即发官网的解决方案:
new flatfileitemwriterbuilder()
      .name(itemwritername)
      .resource(outputresource)
      .lineaggregator(lineaggregator)
      .headercallback(
      h -> {
               system.out.println(header);
               h.write('\ufeff');//只需加这一行
               h.write(header);
           }
      )
      .build();




paulwong 2021-03-23 10:30
]]>
jsr-303 bean validation - date string validation http://www.blogjava.net/paulwong/archive/2021/02/25/435810.htmlpaulwongpaulwongthu, 25 feb 2021 01:44:00 gmthttp://www.blogjava.net/paulwong/archive/2021/02/25/435810.htmlhttp://www.blogjava.net/paulwong/comments/435810.htmlhttp://www.blogjava.net/paulwong/archive/2021/02/25/435810.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435810.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435810.html其实可以新加一个方法返回date类型,再配合@future@past 进行验证。

@future(message = "invalid cn_id_info.expire_date.")
private localdate getvalidexpiredate() {
    try {
        return localdate.parse(this.datestring, datetimeformatter.ofpattern("yyyy-mm-dd"));
    } catch (exception e) {
        return null;
    }
}

此方法对datestring进行解释,返回localdate,如果datestring为空或格式错误,则返回空,再配合@future 进行是否未来日期的验证。



paulwong 2021-02-25 09:44
]]>
jsr-303 bean validation - conditional validationhttp://www.blogjava.net/paulwong/archive/2021/02/25/435809.htmlpaulwongpaulwongthu, 25 feb 2021 01:24:00 gmthttp://www.blogjava.net/paulwong/archive/2021/02/25/435809.htmlhttp://www.blogjava.net/paulwong/comments/435809.htmlhttp://www.blogjava.net/paulwong/archive/2021/02/25/435809.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435809.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435809.html这种方法避免了自定义校验器而增加类。


@asserttrue(message = "missing bank_card_img_info.img")
private boolean getvalidimg() {
    if(ynenum.y.code.equals(super.getneedchecked())) {
            return stringutils.hastext(this.img);
        }
        return null;//igore checking.
}

这个是当needchecked为y的时候才执行检查img变量是否为空。
有几点注意:
  1. 方法名称要以get开头
  2. 返回类型用boolean,而不用boolean
  3. 返回值有三种:true,false,null如果是null则当成通过,与true的结果一样


paulwong 2021-02-25 09:24
]]>
jsr-303 bean validationhttp://www.blogjava.net/paulwong/archive/2021/01/28/435786.htmlpaulwongpaulwongthu, 28 jan 2021 02:35:00 gmthttp://www.blogjava.net/paulwong/archive/2021/01/28/435786.htmlhttp://www.blogjava.net/paulwong/comments/435786.htmlhttp://www.blogjava.net/paulwong/archive/2021/01/28/435786.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435786.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435786.html
jsr-303 bean validation则提供了这样的便捷。

只要在java bean中需要验证的字段加@notnull这种标签,然后在servise中的输入参数中加@valid标签,则就激活验证流程。
也可以编程的方式自己验证:
@messageendpoint
//@validated
public class mqmessageccdvalidator {
    
    private static final logger logger = loggerfactory.getlogger(mqmessageccdvalidator.class);
    
    @autowired
    private validator validator;
    
    @serviceactivator
    public mqmessage validate(/* @valid */ message> requestmessage) {
        set>> set = validator.validate(requestmessage.getpayload());
        if(collectionutils.isnotempty(set)) {
            compositeexception compositeexception = new compositeexception();
            set.foreach(
                constraintviolation -> {
                                            logger.info("{}", constraintviolation);
                                            reqinfovalidationexception exception =
                                                    new reqinfovalidationexception(constraintviolation.getmessage());
                                            compositeexception.addexception(exception);
                                       }
            );
            throw new messagehandlingexception(requestmessage, compositeexception);
        }
        
        return requestmessage.getpayload();
    }

}

自定义验证规则
可用标签来做,以下为验证手机号的规则:
import static java.lang.annotation.retentionpolicy.runtime;

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.target;

import javax.validation.constraint;
import javax.validation.payload;
import javax.validation.reportassingleviolation;
import javax.validation.constraints.pattern;

@retention(runtime)
@target(value = { elementtype.field, elementtype.parameter, elementtype.annotation_type })
@constraint(validatedby = {})
@reportassingleviolation
@pattern(regexp = "^1[3-9]\\d{9}$")
public @interface chinaphone {
    string message() default "invalid chinese mobile no.";
    class[] groups() default {};
    classextends payload>[] payload() default {};
}

如果比较复杂的验证规则,则参见:


how to use java bean validation in spring boot


complete guide to validation with spring boot


spring jms validate messages using jsr-303 bean validation


spring rest validation example
spring boot 整合 bean validation 校验数据



paulwong 2021-01-28 10:35
]]>
spring integration header问题http://www.blogjava.net/paulwong/archive/2020/10/20/435696.htmlpaulwongpaulwongtue, 20 oct 2020 06:56:00 gmthttp://www.blogjava.net/paulwong/archive/2020/10/20/435696.htmlhttp://www.blogjava.net/paulwong/comments/435696.htmlhttp://www.blogjava.net/paulwong/archive/2020/10/20/435696.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435696.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435696.html
.headerfilter("api-key", "content-type", "x-powered-by", "content-language", "transfer-encoding", "cache-control", "keep-alive", "set-cookie")



paulwong 2020-10-20 14:56
]]>
resttemplate处理请求状态码为非200的返回数据http://www.blogjava.net/paulwong/archive/2020/10/16/435694.htmlpaulwongpaulwongfri, 16 oct 2020 08:54:00 gmthttp://www.blogjava.net/paulwong/archive/2020/10/16/435694.htmlhttp://www.blogjava.net/paulwong/comments/435694.htmlhttp://www.blogjava.net/paulwong/archive/2020/10/16/435694.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435694.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435694.html
resttemplate提供了多种便捷访问远程http服务的方法,能够大大提高客户端的编写效率。

调用resttemplate的默认构造函数,resttemplate对象在底层通过使用java.net包下的实现创建http 请求,

可以通过使用clienthttprequestfactory指定不同的http请求方式。

clienthttprequestfactory接口主要提供了两种实现方式

1、一种是simpleclienthttprequestfactory,使用j2se提供的方式(既java.net包提供的方式)创建底层的http请求连接。

2、一种方式是使用httpcomponentsclienthttprequestfactory方式,底层使用httpclient访问远程的http服务,使用httpclient可以配置连接池和证书等信息。

默认的 resttemplate 有个机制是请求状态码非200 就抛出异常,会中断接下来的操作。如果不想中断对结果数据得解析,可以通过覆盖默认的 responseerrorhandler ,见下面的示例,示例中的方法中基本都是空方法,只要对haserror修改下,让他一直返回true,即是不检查状态码及抛异常了。

package com.example.demo.web.config;

import java.io.ioexception;

import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.http.client.clienthttprequestfactory;
import org.springframework.http.client.clienthttpresponse;
import org.springframework.http.client.simpleclienthttprequestfactory;
import org.springframework.web.client.responseerrorhandler;
import org.springframework.web.client.resttemplate;

@configuration
public class resttemplateconfig {
    
    @bean
    public resttemplate resttemplate(clienthttprequestfactory factory) throws exception {
        resttemplate resttemplate = new resttemplate(factory);
        responseerrorhandler responseerrorhandler = new responseerrorhandler() {
            @override
            public boolean haserror(clienthttpresponse clienthttpresponse) throws ioexception {
                return true;
            }
            @override
            public void handleerror(clienthttpresponse clienthttpresponse) throws ioexception {
            }
        };
        resttemplate.seterrorhandler(responseerrorhandler);
        return resttemplate;
    }
    
    @bean
    public clienthttprequestfactory simpleclienthttprequestfactory(){
        simpleclienthttprequestfactory factory = new simpleclienthttprequestfactory();
        //读取超时5秒
        factory.setreadtimeout(5000);
        //连接超时15秒
        factory.setconnecttimeout(15000);
        return factory;
    }
}

resttemppate运用实例

package com.example.demo.web.controller;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.http.responseentity;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;
import org.springframework.web.client.resttemplate;

import com.example.demo.domain.book;

@restcontroller
public class testbookcontroller {
    private logger logger = loggerfactory.getlogger(getclass());
    
      @autowired
      private resttemplate resttemplate;
      
      @getmapping("/testaddbook")
      public book testaddbook() {
              book book = new book();
              responseentity responseentity = resttemplate.postforentity( "http://localhost:8061/book", book , book.class);
              return responseentity.getbody();
      }

}

其他方法,catch httpstatuscodeexception e.getresponsebodyasstring()
try {
    responseentity response = resttemplate.exchange(websvcurl,
        httpmethod.post, 
        requestentity,
        component.class);
catch (httpstatuscodeexception e) {
    list customheader = e.getresponseheaders().get("x-app-err-id");
    string svcerrormessageid = "";
    if (customheader != null) {
        svcerrormessageid = customheader.get(0);                
    }
    throw new customexception(e.getmessage(), e, svcerrormessageid);
    // you can get the body too but you will have to deserialize it yourself
    
// e.getresponsebodyasbytearray()
    
// e.getresponsebodyasstring()
}





paulwong 2020-10-16 16:54
]]>
error handling in spring integration - how to get all the errors thrown in multiple threads and send them to the error-channelhttp://www.blogjava.net/paulwong/archive/2020/10/15/435693.htmlpaulwongpaulwongthu, 15 oct 2020 11:21:00 gmthttp://www.blogjava.net/paulwong/archive/2020/10/15/435693.htmlhttp://www.blogjava.net/paulwong/comments/435693.htmlhttp://www.blogjava.net/paulwong/archive/2020/10/15/435693.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435693.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435693.html
@bean
public integrationflow provisionuserflow() {
return
    integrationflows.from("input.channel")
    .publishsubscribechannel(executors.newcachedthreadpool(),
        s -> s.applysequence(true)
            .subscribe(f -> f.enrichheaders(e -> e.header(messageheaders.error_channel, "errorchannel", true))
                .handle(provisionera, "provision")
                .channel("aggregatorchannel")
            )
            .subscribe(f -> f.enrichheaders(e -> e.header(messageheaders.error_channel, "errorchannel", true))
                .handle(provisionerb, "provision")
                .channel("aggregatorchannel"))
            )
        .get();
}

@bean
public integrationflow aggregateflow() {
    return integrationflows.from("aggregatorchannel")
                    .channel( aggregatorchannel)
                    .aggregate( a -> a.processor( collect, "aggregatingmethod"))
                    .get();
}

@transformer( inputchannel = "errorchannel", outputchannel = "aggregatorchannel")
public message errorchannelhandler(errormessage errormessage) throws runtimeexception {

    message failedmessage =  ((messagingexception) errormessage.getpayload()).getfailedmessage();

    exception exception = (exception) errormessage.getpayload();

    return  messagebuilder.withpayload( exception.getmessage())
                                       .copyheadersifabsent( failedmessage.getheaders() )
                                       .build();
}






paulwong 2020-10-15 19:21
]]>
spring integration子flowhttp://www.blogjava.net/paulwong/archive/2020/10/15/435692.htmlpaulwongpaulwongthu, 15 oct 2020 03:29:00 gmthttp://www.blogjava.net/paulwong/archive/2020/10/15/435692.htmlhttp://www.blogjava.net/paulwong/comments/435692.htmlhttp://www.blogjava.net/paulwong/archive/2020/10/15/435692.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435692.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435692.html split之后,可以将message分给不同的子flow处理,配置如下:
@bean
public integrationflow parallelsplitrouteaggregateflow() {
    return integrationflows
            .from(http.inboundgateway("/trigger"))
            .handle((p, h) -> arrays.aslist(1, 2, 3))
            .split()
            .channel(messagechannels.executor(executors.newcachedthreadpool()))
            .route(o -> o % 2 == 0, m -> m
                    .subflowmapping(true, sf -> sf.gateway(oddflow()))
                    .subflowmapping(false, sf -> sf.gateway(evenflow())))
            .aggregate()
            .get();
}

@bean
public integrationflow oddflow() {
    return flow -> flow.handle((payload, headers) -> "odd");
}

@bean
public integrationflow evenflow() {
    return flow -> flow.handle((payload, headers) -> "even");
}




paulwong 2020-10-15 11:29
]]>
怀旧框架集合http://www.blogjava.net/paulwong/archive/2020/10/09/435687.htmlpaulwongpaulwongfri, 09 oct 2020 11:14:00 gmthttp://www.blogjava.net/paulwong/archive/2020/10/09/435687.htmlhttp://www.blogjava.net/paulwong/comments/435687.htmlhttp://www.blogjava.net/paulwong/archive/2020/10/09/435687.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435687.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435687.html阅读全文

paulwong 2020-10-09 19:14
]]>
spring retry框架——看这篇就够了http://www.blogjava.net/paulwong/archive/2020/09/15/435662.htmlpaulwongpaulwongtue, 15 sep 2020 05:39:00 gmthttp://www.blogjava.net/paulwong/archive/2020/09/15/435662.htmlhttp://www.blogjava.net/paulwong/comments/435662.htmlhttp://www.blogjava.net/paulwong/archive/2020/09/15/435662.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/435662.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/435662.htmlhttps://my.oschina.net/marvelcode/blog/4563352



paulwong 2020-09-15 13:39
]]>
logback for springhttp://www.blogjava.net/paulwong/archive/2019/11/19/434914.htmlpaulwongpaulwongtue, 19 nov 2019 07:14:00 gmthttp://www.blogjava.net/paulwong/archive/2019/11/19/434914.htmlhttp://www.blogjava.net/paulwong/comments/434914.htmlhttp://www.blogjava.net/paulwong/archive/2019/11/19/434914.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/434914.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/434914.html中查找对应logger,使用其配置的appender组件打印日志,如无法找到对应的logger,则使用对应的appender打印日志。

其中appender是用来输出日志,有file和console两个实现,console则是向控制台输出日志,而file则是向文件输出日志。
rolling file appender中,有rollingpolicy和triggerpolicy两个主要属性,rollingpolicy是确定如何处理日志文件,而triggerpolicy则是确定何时处理日志文件。

如果要使用spring针对logback的一些功能,如profile等,则要将logback.xml的配置文件命名为logback-spring.xml,并在spring中配置,logging.config= logback-spring.xml。

spring会将logging.file、logging.path这些配置转成系统变量log_file、log_path,可在配置文件中直接引用,如${log_file}。

如果logback配置文件要spring的其他属性,则要使用如下标签:
<springproperty scope="context" name="loglevel" source="log.level"/>

如果要使用logback的一些常用属性,可引入:
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
如console appender,此resource在spring-boot-version.jar中。


=========================================
看完这个不会配置 logback ,请你吃瓜!


logback解析——appender


springboot中logback.xml使用application.yml中属性


springboot使用logback-spring.xml配置讲解


logback配置


logback中如何自定义灵活的日志过滤规则


spring boot中的日志


spring boot与logback总结


springboot logback 配置参数迁移到配置中心 apollo



paulwong 2019-11-19 15:14
]]>
spring-loaded热部署http://www.blogjava.net/paulwong/archive/2016/09/11/431784.htmlpaulwongpaulwongsun, 11 sep 2016 02:40:00 gmthttp://www.blogjava.net/paulwong/archive/2016/09/11/431784.htmlhttp://www.blogjava.net/paulwong/comments/431784.htmlhttp://www.blogjava.net/paulwong/archive/2016/09/11/431784.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/431784.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/431784.html
spring-loaded是一个对于jvm代理运行时期改变类文件的重载(重新加载),它转换类loadtime让他们服从后重新加载。不像“热代码替换”只允许一次简单的改变jvm运行(例如更改方法体)spring-loaded允许您添加/修改/删除/字段/方法构造函数。注释类型/方法/字段/构造函数也可以修改和可以添加/删除/修改值的枚举类型。

有什么好处?

开发测试阶段:能够在启动后动态更改代码调试,无需重启减少切换debug时间(ps:对于eclipse而言,在debug时期只能做到动态更新方法体不能增加)
对于线上测试发布阶段: 能够在出现问题后直接替换class文件而不重启应用(ps:对于外部提供的服务jar形式同样能做到)
怎么使用?

项目地址



第一步:下载文件


第二步:配置jvm启动参数

eclipse
eclipse:run as --> run configurations --> arguments -->> vm arguments
-javaagent:e:\repository\org\springframework\spring-load\springloaded-1.2.5.release.jar 
-noverify -dspringloaded=verbose
详细描述:
-javaagent: 配置java代理使用下载后的jar包路径
-noverify: 禁用字节码验证
-dspringloaded=verbose 显示springloaded时的详细信息


java命令启动

java -javaagent:e:\repository\org\springframework\spring-load\springloaded-1.2.5.release.jar -noverify test  类似 

java jar包动态替换

1.打成runnable jar
2.命令启动:

java -javaagent:e:\repository\org\springframework\spring-load\springloaded-1.2.5.release.jar -noverify -dspringloaded=watchjars=main.jar main.jar

/**  * 类test.java的实现描述:todo 类实现描述   * @author administrator 2016年7月4日 下午4:55:59  */ public class test {     public static void main(string[] args) throws interruptedexception {          while(true) {             try {                 println();                 thread.sleep(1000);             } catch (throwable e) {                  e.printstacktrace();              }          }       }     public static void println() {          system.out.println("112222221222222");          }  } 

改变为

/**  * 类test.java的实现描述:todo 类实现描述   * @author administrator 2016年7月4日 下午4:55:59  */ public class test {     public static void main(string[] args) throws interruptedexception {          while(true) {             try {                 println();                 thread.sleep(1000);             } catch (throwable e) {                  e.printstacktrace();              }          }       }     public static void println() {          system.out.println("test replace jar");          }  } 
3.重新打包替换
ps:实测在window下无用 手上无linux机器待测试




1

paulwong 2016-09-11 10:40
]]>
spring mvc整合nettyhttp://www.blogjava.net/paulwong/archive/2016/04/19/430146.htmlpaulwongpaulwongtue, 19 apr 2016 05:27:00 gmthttp://www.blogjava.net/paulwong/archive/2016/04/19/430146.htmlhttp://www.blogjava.net/paulwong/comments/430146.htmlhttp://www.blogjava.net/paulwong/archive/2016/04/19/430146.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/430146.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/430146.htmlhttp://wenku.baidu.com/view/4573aba4ce2f0066f53322e8.html

paulwong 2016-04-19 13:27
]]>
spring iohttp://www.blogjava.net/paulwong/archive/2015/10/30/427986.htmlpaulwongpaulwongfri, 30 oct 2015 06:05:00 gmthttp://www.blogjava.net/paulwong/archive/2015/10/30/427986.htmlhttp://www.blogjava.net/paulwong/comments/427986.htmlhttp://www.blogjava.net/paulwong/archive/2015/10/30/427986.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/427986.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/427986.html如此一来,不同模块或者与外部进行集成时,依赖处理就需要各自对应版本号。
比如,较新spring与较老的quartz,它们集成就会遇到问题,给搭建和升级带来不便。

因此spring io platform应运而生,只要项目中引入了它,外部集成时依赖关系无需版本号

<dependency>
 <groupid>org.springframeworkgroupid>
 <artifactid>spring-coreartifactid> 
dependency>

spring io platform只是一个pom文件,记录了spring与其他开源项目对应的版本。
省去了版本号,也就省去了处理依赖时的问题,因为spring io platform中有最优的版本。

paulwong 2015-10-30 14:05
]]>
spring面试问答top 25http://www.blogjava.net/paulwong/archive/2015/04/30/424783.htmlpaulwongpaulwongthu, 30 apr 2015 05:29:00 gmthttp://www.blogjava.net/paulwong/archive/2015/04/30/424783.htmlhttp://www.blogjava.net/paulwong/comments/424783.htmlhttp://www.blogjava.net/paulwong/archive/2015/04/30/424783.html#feedback1http://www.blogjava.net/paulwong/comments/commentrss/424783.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/424783.html阅读全文

paulwong 2015-04-30 13:29
]]>
spring cache之concurrentmapcachemanager改造http://www.blogjava.net/paulwong/archive/2015/02/25/423034.htmlpaulwongpaulwongwed, 25 feb 2015 08:34:00 gmthttp://www.blogjava.net/paulwong/archive/2015/02/25/423034.htmlhttp://www.blogjava.net/paulwong/comments/423034.htmlhttp://www.blogjava.net/paulwong/archive/2015/02/25/423034.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/423034.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/423034.html
  1. pom.xml中加入依赖包
            <dependency>
                <groupid>com.google.guavagroupid>
                <artifactid>guavaartifactid>
                <version>18.0version>
            dependency>

  2. 改造cachemanager,myconcurrentmapcachemanager
    package com.paul.common.cache;
    /*
     * 凯发天生赢家一触即发官网 copyright 2002-2014 the original author or authors.
     *
     * licensed under the apache license, version 2.0 (the "license");
     * you may not use this file except in compliance with the license.
     * you may obtain a copy of the license at
     *
     *      
    http://www.apache.org/licenses/license-2.0
     *
     * unless required by applicable law or agreed to in writing, software
     * distributed under the license is distributed on an "as is" basis,
     * without warranties or conditions of any kind, either express or implied.
     * see the license for the specific language governing permissions and
     * limitations under the license.
     
    */

    import java.util.collection;
    import java.util.collections;
    import java.util.map;
    import java.util.concurrent.concurrenthashmap;
    import java.util.concurrent.concurrentmap;
    import java.util.concurrent.timeunit;

    import org.springframework.cache.cache;
    import org.springframework.cache.cachemanager;
    import org.springframework.cache.concurrent.concurrentmapcache;

    import com.google.common.cache.cachebuilder;

    /**
     * {
    @link cachemanager} implementation that lazily builds {@link concurrentmapcache}
     * instances for each {
    @link #getcache} request. also supports a 'static' mode where
     * the set of cache names is pre-defined through {
    @link #setcachenames}, with no
     * dynamic creation of further cache regions at runtime.
     *
     * 

    note: this is by no means a sophisticated cachemanager; it comes with no
     * cache configuration options. however, it may be useful for testing or simple
     * caching scenarios. for advanced local caching needs, consider
     * {@link org.springframework.cache.guava.guavacachemanager} or
     * {
    @link org.springframework.cache.ehcache.ehcachecachemanager}.
     *
     * 
    @author juergen hoeller
     * 
    @since 3.1
     * 
    @see concurrentmapcache
     
    */
    public class myconcurrentmapcachemanager implements cachemanager {

        private final concurrentmap cachemap = new concurrenthashmap(16);

        private boolean dynamic = true;

        private boolean allownullvalues = true;
        
        private long expiretime = 30;
        
        private long maximumsize = 100;


        /**
         * construct a dynamic concurrentmapcachemanager,
         * lazily creating cache instances as they are being requested.
         
    */
        public myconcurrentmapcachemanager() {
        }

        /**
         * construct a static concurrentmapcachemanager,
         * managing caches for the specified cache names only.
         
    */
        public myconcurrentmapcachemanager(long expiretime, long maximumsize) {
            if(expiretime > 0)
                this.expiretime = expiretime;
            if(maximumsize > 0)
                this.maximumsize = maximumsize;
        }


        /**
         * specify the set of cache names for this cachemanager's 'static' mode.
         * 

    the number of caches and their names will be fixed after a call to this method,
         * with no creation of further cache regions at runtime.
         * 

    calling this with a {@code null} collection argument resets the
         * mode to 'dynamic', allowing for further creation of caches again.
         
    */
        public void setcachenames(collection cachenames) {
            if (cachenames != null) {
                for (string name : cachenames) {
                    this.cachemap.put(name, createconcurrentmapcache(name));
                }
                this.dynamic = false;
            }
            else {
                this.dynamic = true;
            }
        }

        /**
         * specify whether to accept and convert {
    @code null} values for all caches
         * in this cache manager.
         * 

    default is "true", despite concurrenthashmap itself not supporting {@code null}
         * values. an internal holder object will be used to store user-level {
    @code null}s.
         * 

    note: a change of the null-value setting will reset all existing caches,
         * if any, to reconfigure them with the new null-value requirement.
         */
        public void setallownullvalues(boolean allownullvalues) {
            if (allownullvalues != this.allownullvalues) {
                this.allownullvalues = allownullvalues;
                // need to recreate all cache instances with the new null-value configuration
                for (map.entry entry : this.cachemap.entryset()) {
                    entry.setvalue(createconcurrentmapcache(entry.getkey()));
                }
            }
        }

        /**
         * return whether this cache manager accepts and converts {
    @code null} values
         * for all of its caches.
         
    */
        public boolean isallownullvalues() {
            return this.allownullvalues;
        }


        @override
        public collection getcachenames() {
            return collections.unmodifiableset(this.cachemap.keyset());
        }

        @override
        public cache getcache(string name) {
            cache cache = this.cachemap.get(name);
            if (cache == null && this.dynamic) {
                synchronized (this.cachemap) {
                    cache = this.cachemap.get(name);
                    if (cache == null) {
                        cache = createconcurrentmapcache(name);
                        this.cachemap.put(name, cache);
                    }
                }
            }
            return cache;
        }

        /**
         * create a new concurrentmapcache instance for the specified cache name.
         * 
    @param name the name of the cache
         * 
    @return the concurrentmapcache (or a decorator thereof)
         
    */
        protected cache createconcurrentmapcache(string name) {
            //return new concurrentmapcache(name, isallownullvalues());
            //此处改用google guava的构造manager方式
            return new concurrentmapcache(name,
                                            cachebuilder.newbuilder()
                                                        .expireafterwrite(this.expiretime, timeunit.minutes)
                                                        .maximumsize(this.maximumsize)
                                                        .build()
                                                        .asmap(), 
                                            isallownullvalues());
        }

    }



  3. 配置想着bean, cache-concurrentmap-applicationcontext.xml
    xml version="1.0" encoding="utf-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi
    ="http://www.w3.org/2001/xmlschema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:cache
    ="http://www.springframework.org/schema/cache"
        xmlns:p
    ="http://www.springframework.org/schema/p"
        xmlns:c
    ="http://www.springframework.org/schema/c"
        xmlns:jee
    ="http://www.springframework.org/schema/jee"
        xmlns:util
    ="http://www.springframework.org/schema/util"
        xsi:schemalocation
    ="http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-3.0.xsd
              http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/cache
              http://www.springframework.org/schema/cache/spring-cache.xsd
              http://www.springframework.org/schema/jee 
              http://www.springframework.org/schema/jee/spring-jee.xsd
              http://www.springframework.org/schema/util
              http://www.springframework.org/schema/util/spring-util.xsd"
    >

        <cache:annotation-driven />

        
        
        <bean id="cachemanager"
            class
    ="com.paul.common.cache.myconcurrentmapcachemanager">
            <constructor-arg index="0" value="1" />
            <constructor-arg index="1" value="5000" />
        bean>    
        
    beans>


  4. 通过注释进行使用
    /*
     * jboss, home of professional open source
     * 凯发天生赢家一触即发官网 copyright 2014, red hat, inc. and/or its affiliates, and individual
     * contributors by the @authors tag. see the 凯发天生赢家一触即发官网 copyright.txt in the
     * distribution for a full listing of individual contributors.
     *
     * licensed under the apache license, version 2.0 (the "license");
     * you may not use this file except in compliance with the license.
     * you may obtain a copy of the license at
     * 
    http://www.apache.org/licenses/license-2.0
     * unless required by applicable law or agreed to in writing, software
     * distributed under the license is distributed on an "as is" basis,
     * without warranties or conditions of any kind, either express or implied.
     * see the license for the specific language governing permissions and
     * limitations under the license.
     
    */
    package com.paul.springmvc.data;

    import java.util.list;

    import javax.persistence.entitymanager;
    import javax.persistence.criteria.criteriabuilder;
    import javax.persistence.criteria.criteriaquery;
    import javax.persistence.criteria.root;

    import org.springframework.beans.factory.annotation.autowired;
    import org.springframework.cache.annotation.cacheevict;
    import org.springframework.cache.annotation.cacheable;
    import org.springframework.stereotype.repository;
    import org.springframework.transaction.annotation.transactional;

    import com.paul.springmvc.model.member;

    @repository
    @transactional
    public class memberdaoimpl implements memberdao {
        @autowired
        private entitymanager em;

        @cacheable(value = "my-local-cache", key = "#id")
        public member findbyid(long id) {
            system.out.println("memberdaoimpl no cache");
            return em.find(member.class, id);
        }

        public member findbyemail(string email) {
            criteriabuilder cb = em.getcriteriabuilder();
            criteriaquery criteria = cb.createquery(member.class);
            root member = criteria.from(member.class);

            /*
             * swap criteria statements if you would like to try out type-safe criteria queries, a new
             * feature in jpa 2.0 criteria.select(member).orderby(cb.asc(member.get(member_.name)));
             
    */

            criteria.select(member).where(cb.equal(member.get("email"), email));
            return em.createquery(criteria).getsingleresult();
        }

        public list findallorderedbyname() {
            criteriabuilder cb = em.getcriteriabuilder();
            criteriaquery criteria = cb.createquery(member.class);
            root member = criteria.from(member.class);

            /*
             * swap criteria statements if you would like to try out type-safe criteria queries, a new
             * feature in jpa 2.0 criteria.select(member).orderby(cb.asc(member.get(member_.name)));
             
    */

            criteria.select(member).orderby(cb.asc(member.get("name")));
            return em.createquery(criteria).getresultlist();
        }

        @cacheevict(value="my-local-cache",allentries=true,beforeinvocation=true)//清空所有缓存
        public void register(member member) {
            em.persist(member);
            return;
        }
    }


paulwong 2015-02-25 16:34
]]>
spring cache资源http://www.blogjava.net/paulwong/archive/2015/02/25/423032.htmlpaulwongpaulwongwed, 25 feb 2015 08:04:00 gmthttp://www.blogjava.net/paulwong/archive/2015/02/25/423032.htmlhttp://www.blogjava.net/paulwong/comments/423032.htmlhttp://www.blogjava.net/paulwong/archive/2015/02/25/423032.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/423032.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/423032.html
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/htmlsingle/#cache

spring concurrentmap manager加过期策略


组合key


spring cache抽象详解


注释驱动的 spring cache 缓存介绍




paulwong 2015-02-25 16:04
]]>
architecture for redis cache & mongo for persistencehttp://www.blogjava.net/paulwong/archive/2015/01/04/422026.htmlpaulwongpaulwongsun, 04 jan 2015 07:50:00 gmthttp://www.blogjava.net/paulwong/archive/2015/01/04/422026.htmlhttp://www.blogjava.net/paulwong/comments/422026.htmlhttp://www.blogjava.net/paulwong/archive/2015/01/04/422026.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/422026.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/422026.html

architecture for redis cache & mongo for persistence


mongodb with redis


caching data in spring using redis


springside redis


spring cache注解 redis
















paulwong 2015-01-04 15:50
]]>
spring-sessionhttp://www.blogjava.net/paulwong/archive/2014/11/19/420309.htmlpaulwongpaulwongwed, 19 nov 2014 10:23:00 gmthttp://www.blogjava.net/paulwong/archive/2014/11/19/420309.htmlhttp://www.blogjava.net/paulwong/comments/420309.htmlhttp://www.blogjava.net/paulwong/archive/2014/11/19/420309.html#feedback1http://www.blogjava.net/paulwong/comments/commentrss/420309.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/420309.html阅读全文

paulwong 2014-11-19 18:23
]]>
spring boothttp://www.blogjava.net/paulwong/archive/2014/10/11/418634.htmlpaulwongpaulwongsat, 11 oct 2014 12:34:00 gmthttp://www.blogjava.net/paulwong/archive/2014/10/11/418634.htmlhttp://www.blogjava.net/paulwong/comments/418634.htmlhttp://www.blogjava.net/paulwong/archive/2014/10/11/418634.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/418634.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/418634.html spring boot 在 spring 生态中的位置:






paulwong 2014-10-11 20:34
]]>
spring对httpsession的重新封闭http://www.blogjava.net/paulwong/archive/2014/08/19/417090.htmlpaulwongpaulwongtue, 19 aug 2014 01:13:00 gmthttp://www.blogjava.net/paulwong/archive/2014/08/19/417090.htmlhttp://www.blogjava.net/paulwong/comments/417090.htmlhttp://www.blogjava.net/paulwong/archive/2014/08/19/417090.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/417090.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/417090.htmlhttps://github.com/spring-projects/spring-session/tree/master/samples

paulwong 2014-08-19 09:13
]]>
自定义注释与操作行为记录http://www.blogjava.net/paulwong/archive/2014/07/25/416201.htmlpaulwongpaulwongfri, 25 jul 2014 06:56:00 gmthttp://www.blogjava.net/paulwong/archive/2014/07/25/416201.htmlhttp://www.blogjava.net/paulwong/comments/416201.htmlhttp://www.blogjava.net/paulwong/archive/2014/07/25/416201.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/416201.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/416201.html自定义注释就是一个标记,一个信息收集器,如果配合spring的aop使用,可以记录用户的操作行为。

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

/**
 * 新增的用法:@audit(behaviour="新增了专题", 
 *            value="#{args[0].colsubject}")
 *
 * 修改的用法:@audit(behaviour="修改了专题", id="#{args[0].colsubject.id}", 
 *            classname="com.paul.program.colsubject.valueobject.colsubject",
 *            value="#{args[0].colsubject}")
 *
 * 删除的用法:@audit(behaviour="删除了专题", id="#{args[0].colsubject.id}"
 *             classname="com.paul.program.colsubject.valueobject.colsubject")
 *             
 * 
@author paul
 *
 
*/
@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface audit {
    
    string id() default "";
    string classname() default "";
    string collectionname() default "";
    string value() default "";
    string behaviour();

}


值对象
auditdata.java
package com.paul.common.audit;

import java.io.serializable;
import java.util.date;

import org.codehaus.jackson.annotate.jsonproperty;
import org.codehaus.jackson.map.annotate.jsonserialize;
import org.springframework.data.annotation.createdby;
import org.springframework.data.annotation.createddate;
import org.springframework.data.annotation.id;
import org.springframework.data.mongodb.core.mapping.document;
import org.springframework.data.mongodb.core.mapping.field;

import com.paul.common.util.jackson.customjsondateserializer;

@document(collection = "auditdata")
public class auditdata implements serializable{

    private static final long serialversionuid = -4011585863836336249l;
    
    @id
    private string id;
    
    @createdby
    @field("userid")
    @jsonproperty("userid")
    private string userid;
    
    @createddate
    @field("createdate")
    @jsonproperty("createdate")
    @jsonserialize(using = customjsondateserializer.class)
    private date createdate;
    
    private string behaviour;
    
    @field("newvalue")
    @jsonproperty("newvalue")
    private string newvalue;
    
    @field("oldvalue")
    @jsonproperty("oldvalue")
    private string oldvalue;

    public string getid() {
        return id;
    }

    public void setid(string id) {
        this.id = id;
    }

    public string getuserid() {
        return userid;
    }

    public void setuserid(string userid) {
        this.userid = userid;
    }

    public date getcreatedate() {
        return createdate;
    }

    public void setcreatedate(date createdate) {
        this.createdate = createdate;
    }

    public string getbehaviour() {
        return behaviour;
    }

    public void setbehaviour(string behaviour) {
        this.behaviour = behaviour;
    }


    public string getnewvalue() {
        return newvalue;
    }

    public void setnewvalue(string newvalue) {
        this.newvalue = newvalue;
    }

    public string getoldvalue() {
        return oldvalue;
    }

    public void setoldvalue(string oldvalue) {
        this.oldvalue = oldvalue;
    }

    public string tostring() {
        return "auditdata [id="   id   ", userid="   userid   ", createdate="
                  createdate   ", behaviour="   behaviour   ", newvalue="
                  newvalue   ", oldvalue="   oldvalue   "]";
    }
    

}


rootobject.java
package com.paul.common.audit;

public class rootobject {

    private final object[] args;

    private final object invokedobject;

    private final object returned;

    private final throwable throwned;

    public rootobject(object invokedobject, object[] args, object returned, throwable throwned) {
        super();
        this.invokedobject = invokedobject;
        this.args = args;
        this.returned = returned;
        this.throwned = throwned;
    }

    public object[] getargs() {
        return args;
    }

    public object getinvokedobject() {
        return invokedobject;
    }

    public object getreturned() {
        return returned;
    }

    public throwable getthrowned() {
        return throwned;
    }

}


templateparsercontext.java
package com.paul.common.audit;

import org.springframework.expression.parsercontext;

public class templateparsercontext implements parsercontext {

    public string getexpressionprefix() {
        return "#{";
    }

    public string getexpressionsuffix() {
        return "}";
    }

    public boolean istemplate() {
        return true;
    }
}


获取用户id
package com.paul.common.audit.aware;

import javax.servlet.http.httpservletrequest;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.data.domain.auditoraware;
import org.springframework.stereotype.component;
import org.springframework.web.context.request.requestcontextholder;
import org.springframework.web.context.request.servletrequestattributes;

import com.paul.common.constant.constants;
import com.paul.program.account.valueobject.account;

@component
public class myappauditor implements auditoraware {
    
    private static logger logger = loggerfactory.getlogger(myappauditor.class);

    // get your user name here
    public string getcurrentauditor() {
        
        string result = "n/a";
        try {
            httpservletrequest request = ((servletrequestattributes) requestcontextholder
                    .getrequestattributes()).getrequest();
            account account = (account)request.getsession().getattribute(constants.user_info);
            result = account.getloginname();
        } catch (exception e) {
            logger.error(e.getmessage(), e);
        }
        return result;
    }
}


切面
package com.paul.common.audit.interceptor;

import java.text.simpledateformat;
import java.util.arraylist;
import java.util.date;
import java.util.list;
import java.util.map;
import java.util.concurrent.concurrenthashmap;
import java.util.concurrent.timeunit;

import org.apache.commons.lang.builder.tostringbuilder;
import org.apache.commons.lang.builder.tostringstyle;
import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.mongodb.core.mongotemplate;
import org.springframework.expression.evaluationexception;
import org.springframework.expression.expression;
import org.springframework.expression.expressionparser;
import org.springframework.expression.parseexception;
import org.springframework.expression.parsercontext;
import org.springframework.expression.spel.standard.spelexpressionparser;
import org.springframework.stereotype.component;

import com.paul.common.audit.auditdata;
import com.paul.common.audit.auditdatarequest;
import com.paul.common.audit.rootobject;
import com.paul.common.audit.templateparsercontext;
import com.paul.common.audit.annotation.audit;
import com.paul.common.audit.service.auditdataservice;
import com.paul.common.util.stringutils;

@component
@aspect
public class auditaspect {
    
    private static logger logger = loggerfactory.getlogger(auditaspect.class);
    
    @autowired
    private auditdataservice auditdataservice;
    
    @autowired
    private mongotemplate mongotemplate;
    
    private simpledateformat dateformatprototype = new simpledateformat("yyyy-mm-dd hh:mm:ss");

    private map expressioncache = new concurrenthashmap();

    private expressionparser expressionparser = new spelexpressionparser();

    private parsercontext parsercontext = new templateparsercontext();
    

    protected static void appendthrowablecauses(throwable throwable, string separator, stringbuilder toappendto) {
        list alreadyappendedthrowables = new arraylist();

        while (throwable != null) {
            // append
            toappendto.append(throwable.tostring());
            alreadyappendedthrowables.add(throwable);

            // cause
            throwable cause = throwable.getcause();
            if (cause == null || alreadyappendedthrowables.contains(cause)) {
                break;
            } else {
                throwable = cause;
                toappendto.append(separator);
            }
        }
    }
    
    private string getvaluebyel(string template, object invokedobject, object[] args, object returned, throwable throwned)
    {
        string result = "n/a";
        if(stringutils.isblank(template))
            return result;
        try {
            expression expression = expressioncache.get(template);
            if (expression == null) {
                expression = expressionparser.parseexpression(template, parsercontext);
                expressioncache.put(template, expression);
            }

            object evaluatedmessage = expression.getvalue(new rootobject(invokedobject, args, returned, throwned), object.class);
            result = evaluatedmessage.tostring();
        } catch (parseexception e) {
            logger.error(e.getmessage(), e);
        } catch (evaluationexception e) {
            logger.error(e.getmessage(), e);
        }
        return result;
    }


    protected auditdata buildauditdata(audit auditannotation, object invokedobject, object[] args, object returned, throwable throwned, long durationinnanos) {
        
        auditdata auditdata = new auditdata();
        auditdata.setbehaviour(auditannotation.behaviour());
        string id = this.getvaluebyel(auditannotation.id(), invokedobject, args, returned, throwned);
        auditdata.setoldvalue(this.getoldvaluetostring(id, auditannotation.classname()));
        try {
            string newvalue = this.getvaluebyel(auditannotation.value(), invokedobject, args, returned, throwned);
            auditdata.setnewvalue(newvalue);

            stringbuilder msg = new stringbuilder();

            simpledateformat simpledateformat = (simpledateformat) dateformatprototype.clone();
            msg.append(simpledateformat.format(new date()));
//            auditdata.setcreatedate(simpledateformat.format(new date()));

            msg.append(" ").append(newvalue);

            if (throwned != null) {
                msg.append(" threw '");
                appendthrowablecauses(throwned, ", ", msg);
                msg.append("'");
            }
            msg.append(" by ");
            string user = this.getuser();
            if (user == null) {
                user = "anonymous";
            } 
            msg.append(" in ") .append(timeunit.milliseconds.convert(durationinnanos, timeunit.nanoseconds)).append(" ms");
            return auditdata;
        } catch (exception e) {
            /*stringbuilder msg = new stringbuilder("exception evaluating template '"   template   "': ");
            appendthrowablecauses(e, ", ", msg);
*/
            return auditdata;
        }
    }
    
    private string getoldvaluetostring(/*proceedingjoinpoint proceedingjoinpoint,*/ string id, string classname) 
    {
        string result = "n/a";
        /*string id = "5385be613d2a47eec07c53d4";
        try {
            methodsignature methodsig = (methodsignature) proceedingjoinpoint.getsignature();
            object target = proceedingjoinpoint.gettarget();
            object newvalue = proceedingjoinpoint.getargs()[0];
            string findmethodname = "findone";
            object oldvalue=null;
            method findmethod = target.getclass().getdeclaredmethod(findmethodname, (class[])null);
            oldvalue = findmethod.invoke(target, (object[]) null);

        } catch (exception e) {
            logger.error(e.getmessage(), e);
        }
*/
        if(stringutils.isblank(id) || stringutils.isblank(classname))
            return result;
        
        try {
            object object = mongotemplate.findbyid(id, class.forname(classname));
            result = tostringbuilder.reflectiontostring(object,  tostringstyle.short_prefix_style); 
        } catch (exception e) {
            logger.error(e.getmessage(), e);
        }
        return result;
    }
    
//    @around("execution(* com.paul..**.repository..*(..))")
    @around("@annotation(auditannotation)")
    public object aroundadvice(proceedingjoinpoint proceedingjoinpoint, audit auditannotation) throws throwable {
        
        boolean ok = false;
        object o = null;
        auditdata auditdata = null;
        try 
        {
            auditdata = buildauditdata(auditannotation, proceedingjoinpoint.getthis(), 
                    proceedingjoinpoint.getargs(), 
                    o, null, 10);
            o = proceedingjoinpoint.proceed();
            ok = true;
            return o;
        } 
        finally 
        {
            if (ok)
            {
//                string value = (messageformat.format(auditannotation.value(), proceedingjoinpoint.getargs()));
                try 
                {
                    auditdatarequest auditdatarequest = new auditdatarequest();
                    auditdatarequest.setauditdata(auditdata);
                    auditdataservice.addauditdata(auditdatarequest);
                    logger.info(auditdata   "");
                } 
                catch (exception e) 
                {
                    logger.error(e.getmessage(), e);
                }
            }    
        }
    }
    
    private string getuser()
    {
        return "paul";
    }
    

}


保存至数据库
package com.paul.common.audit.service;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.domain.page;
import org.springframework.stereotype.service;

import com.paul.common.audit.auditdata;
import com.paul.common.audit.auditdatarequest;
import com.paul.common.audit.annotation.audit;
import com.paul.common.audit.repository.auditdatarepository;
import com.paul.program.colsubject.valueobject.colsubjectrequest;

@service
public class auditdataservice {
    
    @autowired
    private auditdatarepository auditdatarepository;
    
//    @audited(message = "save(#{args[0].name}, #{args[0].email}): #{returned?.id}")
    @audit(behaviour="修改了审计", id="#{args[0].colsubject.id}", 
            classname="com.paul.program.colsubject.valueobject.colsubject",
            value="#{args[0].colsubject}")
    public void saveobject(colsubjectrequest colsubjectrequest)
    {
        
    }
    
    @audit(behaviour="删除了专题", id="#{args[0]}",
             classname="com.paul.program.subject.valueobject.subject")
    public void delete(string id) {
    }
    
    @audit(behaviour="新增了专题", value="#{args[0].colsubject}")
    public void add(colsubjectrequest colsubjectrequest) {
    }
    
    public auditdata addauditdata(auditdatarequest auditdatarequest)
    {
        return auditdatarepository.save(auditdatarequest.getauditdata());
    }
    
    public page findall(auditdatarequest auditdatarequest)
    {
        page page = auditdatarepository.findall(auditdatarequest.getpageable());
        return page;
    }

}


dao
package com.paul.common.audit.repository;

import org.springframework.data.repository.pagingandsortingrepository;

import com.paul.common.audit.auditdata;

/**
 * 审计
 * 
 
*/
public interface auditdatarepository extends pagingandsortingrepository{
    
}


paulwong 2014-07-25 14:56
]]>
audit in spring aophttp://www.blogjava.net/paulwong/archive/2014/07/18/415969.htmlpaulwongpaulwongfri, 18 jul 2014 01:50:00 gmthttp://www.blogjava.net/paulwong/archive/2014/07/18/415969.htmlhttp://www.blogjava.net/paulwong/comments/415969.htmlhttp://www.blogjava.net/paulwong/archive/2014/07/18/415969.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/415969.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/415969.html


xebia-spring-security-extras



spring logging using custom annotation



spring mvc and mongodb - auditing actions



audit-aspectj 


paulwong 2014-07-18 09:50
]]>
spring data rest,spring mvc的rest扩展http://www.blogjava.net/paulwong/archive/2014/07/09/415635.htmlpaulwongpaulwongwed, 09 jul 2014 09:36:00 gmthttp://www.blogjava.net/paulwong/archive/2014/07/09/415635.htmlhttp://www.blogjava.net/paulwong/comments/415635.htmlhttp://www.blogjava.net/paulwong/archive/2014/07/09/415635.html#feedback1http://www.blogjava.net/paulwong/comments/commentrss/415635.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/415635.htmlhttp://spring.io/blog/2012/06/26/spring-data-rest-1-0-0-rc1-released

restify your jpa entities


babdev-spring




paulwong 2014-07-09 17:36
]]>
spring data dijkstrahttp://www.blogjava.net/paulwong/archive/2014/07/01/415332.htmlpaulwongpaulwongtue, 01 jul 2014 02:49:00 gmthttp://www.blogjava.net/paulwong/archive/2014/07/01/415332.htmlhttp://www.blogjava.net/paulwong/comments/415332.htmlhttp://www.blogjava.net/paulwong/archive/2014/07/01/415332.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/415332.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/415332.html一大波spring data相关包:
spring data dijkstra sr1 发布,该版本包含如下模块的 59 个问题修复:
  • spring data commons 1.8.1 -  -  -  -

  • spring data jpa 1.6.1 -  -  -  - 

  • spring data mongodb 1.5.1 -  -  -  - 

  • spring data neo4j 3.1.1 -  -  -  - 

  • spring data solr 1.2.1 -  -  -  - 

  • spring data couchbase 1.1.1 -  -  -  - 

  • spring data cassandra 1.0.1 -  -  -  - 

  • spring data elasticsearch 1.0.1 -  -  -  - 

  • spring data gemfire 1.4.1 -  -  -  - 

  • spring data redis 1.3.1 -  -  -  - 

  • spring data rest 2.1.1 -  -  -  - 

建议所有 dijkstra 用户升级,因为包含重要的 bug 修复。



paulwong 2014-07-01 10:49
]]>
在ejb3的session bean中使用spring beanhttp://www.blogjava.net/paulwong/archive/2014/02/12/409777.htmlpaulwongpaulwongwed, 12 feb 2014 08:43:00 gmthttp://www.blogjava.net/paulwong/archive/2014/02/12/409777.htmlhttp://www.blogjava.net/paulwong/comments/409777.htmlhttp://www.blogjava.net/paulwong/archive/2014/02/12/409777.html#feedback0http://www.blogjava.net/paulwong/comments/commentrss/409777.htmlhttp://www.blogjava.net/paulwong/services/trackbacks/409777.html


using spring’s ejb implementation support classes




import javax.ejb.stateless;
import javax.interceptor.interceptors;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.ejb.interceptor.springbeanautowiringinterceptor;

import ch.frankel.blog.ejb.spring.service.client.randomgeneratorservice;

@stateless
@interceptors(springbeanautowiringinterceptor.class)
public class randomgeneratorbean implements randomgeneratorservice {

    @autowired
    private ch.frankel.blog.ejb.spring.service.randomgeneratorservice delegate;

    @override
    public int generatenumber(int lowerlimit, int upperlimit) {

        return delegate.generatenumber(lowerlimit, upperlimit);
    }
}


paulwong 2014-02-12 16:43
]]>
网站地图