Dubbox开发restful风格远程调用服务

dubbox是由dangdang维护的一个dubbo版本分支,最新稳定版本是2.8.4,与原版相比只新增了新功能和默认spring版本升级。

dubbox提供了一个很大的功能就是restful风格远程调用。官方文档:https://dangdangdotcom.github.io/dubbox/rest.html
然后是高性能的序列化支持,以及给予java代码的dubbo配置JavaConfig(可以不用写xml了)

和普通调用一样,首先需要暴露服务,

<dubbo:protocol name="rest" port="8081" server="tomcat" charset="utf-8" extension="dubbox.restful.sample.filter.SampleFilter"/>
// extension支持拦截器的添加和过滤器,多个用逗号分隔,不过我在测试的时候Filter和Interceptor同时添加的时候会导致json序列化出问题。

这里的name必须指定为rest,server可选为tomcat,jetty,netty等等,不过文档显示性能最好的就是tomcat和netty。如果dubbo不是单独启动的话也可以将它嵌入到web容器中,server设置为servlet即可。虽然摆脱了web容器,但是还是引用了嵌入式的tomcat或是jetty。

dubbox默认使用RestEasy来实现restful,resteasy默认使用jackson来序列化,这里想要更改json序列化provider就比较困难了。
服务开发与普通RPC服务开发差不多,不过添加了不同注解来实现restful。

@Component
@Path( "sample" )
// 参数校验
@Service( version = "1.0.0", owner = "jn", validation = "true" )
// 中文支持 json 输出
@Produces({MediaType.APPLICATION_JSON,ContentType.APPLICATION_JSON_UTF_8})
public class SampleServiceImpl implements SampleService {

    @Override
    @POST
    @Path( "sayHello" )
    //@Context server="tjws"或者server="tomcat"或者server="jetty"或者server="servlet"的时候才能工作,
    // 因为只有这几种REST server的实现才提供了servlet容器
    public ResponseMsg sayHello( @Context HttpServletRequest request ) {

        // 设置server="jetty"或者server="tomcat"或者server="servlet"或者server="tjws"的时候才能工作。
        // 另外,目前dubbo的RpcContext是一种比较有侵入性的用法,未来我们很可能会做出重构
        String host = RpcContext.getContext().getRemoteAddressString();

        Object req = RpcContext.getContext().getRequest();
        Object resp = RpcContext.getContext().getResponse();
        // 只有在设置server="jetty"或者server="tomcat"或者server="servlet"的时候,
        // 你才能通过以上方法正确的得到HttpServletRequest和HttpServletResponse,因为只有这几种server实现了servlet容器
        if ( req != null &amp;&amp; req instanceof  HttpServletRequest ) {

            // to do things

        }
        if ( resp != null &amp;&amp; resp instanceof HttpServletResponse ) {

            // to do things
        }
        // 可能返回空
        RpcContext.getContext().getRequest( HttpServletRequest.class );

        User user = new User();
        user.setScore( 11 );
        user.setGender( true );
        user.setName( "中文" );

        ResponseMsg responseMsg = new ResponseMsg();
        responseMsg.setData( user );

        sendJson( JSON.toJSONString( responseMsg ) );

        return responseMsg;
    }

    @Override
    @GET
    @Path( "sayHello" )
    public User sayHello() {

        User user = new User();
        user.setScore( 11 );
        user.setGender( true );
        user.setName( "中文" );

        return user;
    }

    @Override
    @GET   // 实现方法必须添加请求方式,如果对同一个url需要同时支持get和post则添加同一个path使用不同请求方式即可
    @Path( "hello" )
    public String hello() {

        User user = new User();
        user.setScore( 11 );
        user.setGender( true );

        String json = JSON.toJSONString( user );

        sendJson( json );

        return json;
    }

    @Override
    @POST
    @Path( "sayHelloWithValid" )
    public String sayHelloWithValid() {

        System.out.println( getParam() );

        sendJson( "ok" );

        return null;
    }

    private final String UPLOADED_FILE_PATH = "F:\\upload\\";

    @Override
    @POST
    @Path( "upload" )
    @Consumes({MediaType.MULTIPART_FORM_DATA})
    public String fileUpload( MultipartFormDataInput input ) {

        Map&lt;String, List&lt;InputPart&gt;&gt; uploadForm = input.getFormDataMap();
        // key: 表单name属性
        List&lt;InputPart&gt; inputParts = uploadForm.get("file");

        for ( InputPart inputPart : inputParts ) {

            try {

                InputStream inputStream = inputPart.getBody( InputStream.class,null );

                MultivaluedMap&lt;String, String&gt; header = inputPart.getHeaders();
                String fileName = getFileName( header );

                byte [] bytes = IOUtils.toByteArray( inputStream );

                fileName = UPLOADED_FILE_PATH + fileName;

                System.out.println( fileName );

                writeFile( bytes, fileName );

                System.out.println("Done");

            } catch ( IOException e ) {

                e.printStackTrace();
//                sendJson( "exception" );
                return "异常";
            }
        }

//        sendJson( "上传成功" );
        return "上传成功";
    }

    @POST
    @Path( "upload_file" )
    @Override
    @Consumes({MediaType.MULTIPART_FORM_DATA})
    public String fileUpload() {

        HttpServletRequest request = RpcContext.getContext().getRequest( HttpServletRequest.class );

        try {
            request.getInputStream();

            DiskFileItemFactory factory = new DiskFileItemFactory();

//            String path = request.getServletContext().getRealPath("/upload");//设置磁盘缓冲路径

//            factory.setRepository(new File(path));
//            factory.setSizeThreshold(1024*1024);//设置创建缓冲大小

            ServletFileUpload upload = new ServletFileUpload( factory );
            upload.setSizeMax( -1 );//设置上传文件限制大小,-1无上限

            List&lt;FileItem&gt; list = upload.parseRequest( request );

            for( FileItem item : list ){

                if( item.isFormField() ){

                    System.out.println( 111 );

                } else {

                    String fileName = item.getName();//会将完整路径名传过来

                    System.out.println( fileName );

                    InputStream in = item.getInputStream();

                    writeFile( IOUtils.toByteArray( in ), UPLOADED_FILE_PATH + fileName );

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            return "异常";
        }

        return "上传成功";
    }

    private void writeFile( byte[] content, String filename ) throws IOException {

        File file = new File( filename );

        if ( !file.exists() ) {
            file.createNewFile();
        }

        FileOutputStream fop = new FileOutputStream( file );

        fop.write( content );
        fop.flush();
        fop.close();

    }

    private String getFileName( MultivaluedMap&lt;String, String&gt; header ) {

        String[] contentDisposition = header.getFirst("Content-Disposition").split(";");

        for ( String filename : contentDisposition ) {
            if ( filename.trim().startsWith("filename") ) {

                String[] name = filename.split("=");

                return name[1].trim().replaceAll("\"", "");
            }
        }
        return null;
    }

    private void sendJson( String json ){

        HttpServletResponse response = RpcContext.getContext().getResponse( HttpServletResponse.class );

        if ( response != null ) {
            response.setCharacterEncoding( "utf-8" );
            try {
                Writer writer = response.getWriter();

                writer.write( json );
                writer.flush();
                writer.close();

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    private String getParam(){

        HttpServletRequest request = RpcContext.getContext().getRequest( HttpServletRequest.class );

        if ( request == null ) return null;

        try {
            request.setCharacterEncoding( "utf-8" );
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        String reqData = null;
        if ( "GET".equals( request.getMethod() ) ) {
            reqData = request.getParameter( "data" );
            try {
                if ( reqData != null ) {
                    reqData = URLDecoder.decode( reqData, "utf-8" );
                }
            } catch ( Exception e ) {
            }
        } else {
            try {
                reqData = StreamUtils.copyToString( request.getInputStream(), Charset.forName( "utf-8" ) );
                if ( reqData != null ) {
                    reqData = URLDecoder.decode( reqData, "utf-8" );
                }
            } catch ( Exception e ) {
            }
        }
        return reqData;

    }
}

restful文件上传,由于用了resteasy,文件上传也就用的是resteasy的实现,这里会出现中文文件名乱码的问题(页面自然也需要设置编码),这里需要在filter中设置编码

public class SetCharacterEncodingFilter implements Filter{
 public void destroy(){
 }
public void doFilter(ServletRequest request,ServletResponseresponse,
 FilterChainchain) throws IOException, ServletException{
 request.setCharacterEncoding("UTF-8");
 chain.doFilter(request,response);
 }
public void init(FilterConfig filterConfig) throws ServletException{
 }
}

然后将这个filter配置到tomcat配置中去即可。这里有一片比较详细的debug过程:http://blog.csdn.net/HackerSaillen/article/details/64470926

demo地址:https://github.com/Lostars/dubbox/tree/restful-sample

  
BugHome版权所有丨转载请注明出处:https://minei.me/archives/168.html
  

发表评论

电子邮件地址不会被公开。 必填项已用*标注