uniquejava / blog

My notes regarding the vibrating frontend :boom and the plain old java :rofl.
Creative Commons Zero v1.0 Universal
11 stars 5 forks source link

jaxrs #165

Open uniquejava opened 6 years ago

uniquejava commented 6 years ago

从移动硬盘上找来了以前用jaxrs的笔记(庆幸当时是用markdown记录的, 格式还有内容竟然继续好用.. 原样粘贴于此, 方便查找.

https://www.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/twbs_jaxrs_configwebxml.html

simplest jaxrs demo

Here is a tutorial: https://developer.ibm.com/wasdev/docs/jax-rs-basics/

Here is Cyper's action in practice:

Environments

1. Ubuntu 12.04.5 LTS
2. Eclipse JEE 4.4.2
3. IBM WDT 8.5.5.5

1. New web project

name: Hello
project templates: REST Services
Next

Type: disable library configuration
Update deployment descriptor: false
Finish

2. Add the following java files.

MyApplication.java

package com.cyper.hello;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("jaxrs")
public class MyApplication extends Application {

}

WorldResource.java

package com.cyper.hello;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("world")
public class WorldResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("greet")
    public String greeting(){
        return "hello world\n";
    }

}

笔记:

  1. @Path中的路径可以以/开头,也可以不加/,我试了加不加没有区别.
  2. @ApplicationPath也一样,而且可以留空.

3. Run

Can start liberty server from eclipse. and test: curl -i http://localhost:9080/hello/jaxrs/world/greet

其中

hello is web context root
jaxrs is @ApplicationPath
world is @Path at Resource Level
greet is @Path at Method level

4. Export

can export war hello.war and copy to $liberty_home/usr/servers/defaultServer/dropins, The liberty server will monitor this directory and load the app automatically.

Troubleshooting

Add and Remove时提示JDK1.7 is not supported 这是我把Liberty的Runtime Environment从jdk1.7改成了WAS8.5自带的JDK而WAS8.5自带的IBM JDK6

要么 Change Project Facets Java version from 1.7 to 1.6 或者设置Liberty Runtime JRE为JDK1.7

这里有篇文章,如何升级WAS8.5默认JDK到JDK7: http://stackoverflow.com/questions/25223122/java-7-1-in-ibm-websphere/25223414#25223414

两个有用的命令:

$washome/bin/managesdk.sh -listAvailable
$washome/managesdk.sh -enableProfile -profileName AppSrv02 -sdkname 1.7_64

Alternative

还有一种方式是通过在web.xml中配置servlet实现的.和上面的区别如下

1. Generate web.xml

Project >Right Click > Java EE Tools > Generate Deployment Descriptor stub 这步会生成web.xml文件

2. Modify web.xml

<servlet>
    <description>
    JAX-RS Tools Generated - Do not modify</description>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.cyper.hello.MyApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <enabled>true</enabled>
    <async-supported>false</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>
    /jaxrs/*
    </url-pattern>
</servlet-mapping>

3. Modify MyApplication.java

package com.cyper.hello;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

public class MyApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(WorldResource.class);
        return classes;
    }
}

Alternative是我们项目中实际使用的方式.

uniquejava commented 6 years ago

Encoding issue

转自: http://www.boolean.cn/?p=644

在处理Apache CXF搭建的Web服务时,使用了javax.ws.rs.core.Response发现其默认字符集为iso-8859-1,导致中文乱码出现。详细情况请参考以下代码及说明。

@Path("/test")
@GET
@Consumes({ MediaType.APPLICATION_JSON })
// 1、这里解决网页显示的编码问题,如果不需要网页显示,经测试可注释掉
@Produces({ MediaType.APPLICATION_JSON, "text/html; charset=UTF-8" })
public Response test() {
    String string = "寂寞沙洲冷-寂寞沙洲我该思念谁";
    JSONObject json = new JSONObject();
    json.put("url", "www.boolean.cn");
    json.put("value", string);
    return Response.ok().entity(json.toString())
            // 2、这里解决返回Response为UTF-8
            // 如果是网页,可以只保留上面的“1”中的@Produces,这里的header可不用;如果对Response编码,经测试该Header是必须的
            // Content-Type: application/json;charset=UTF-8
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
}

Security & Filter

https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey

自己实现了一个简单的Basic Authentication Filter. 值得注意的是同Resource一样, 需要将这个Filter注册到Application类中.

@Provider
@PreMatching
public class BasicAuthenticationFilter implements ContainerRequestFilter {
    final static Logger logger = LogFactory.getLog(BasicAuthenticationFilter.class);

    final static Config cfg = Config.getInstance();

    public void filter(ContainerRequestContext ctx) throws IOException {
        String authHeader = ctx.getHeaderString(HttpHeaders.AUTHORIZATION);

        try {
            boolean isValidUser = false;

            if (authHeader != null && authHeader.startsWith("Basic")) {
                // Authorization: Basic base64credentials
                String base64Credentials = authHeader.substring("Basic".length()).trim();
                String credentials = new String(Base64.getDecoder().decode(base64Credentials),
                        Charset.forName("UTF-8"));

                // credentials = username:password
                final String[] values = credentials.split(":", 2);
                final String user = cfg.get("app.user");
                final String pwd = cfg.get("app.pwd");
                isValidUser = user.equals(values[0]) && pwd.equals(values[1]);
            }

            if (!isValidUser) {
                throw new NotAuthorizedException("Basic error=\"incorrect_user_or_pwd\"");
            }
        } catch (Exception ex) {

            throw new NotAuthorizedException("Basic error=\"" + ex.getMessage() + "\"");
        }
    }
}
uniquejava commented 6 years ago

File download

见: How to set response header in JAX-RS so that user sees download popup for Excel?

我写的伪代码 未测试.

    @Context ServletContext ctx;
    @Context private HttpServletResponse response;

    @GET
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    @Path("/download/{filename}")
    public StreamingOutput download(@PathParam("filename") String fileName) throws Exception {
        final File file = new File("c:/test.txt");
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "attachment; filename=\""+ file.getName() + "\"");
        return new StreamingOutput() {
            @Override
            public void write(OutputStream output) throws IOException,
                    WebApplicationException {
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                BufferedOutputStream bos =  new BufferedOutputStream(output);
                byte[] buff = new byte[10240];
                while(bis.read(buff)!=-1) {
                    bos.write(buff);
                }
                bis.close();
                bos.flush();
            }
        };
    }