#contents *Hypermedia? [#ieaf3565] -"Hypermedia" は、もはや &wiki(Buzzword); -ここでは、クライアントからの Accept Header で要求されたフォーマットに従って、同じデータを違う形式で返すことを考える -Glassfish(Jersey) で JSON と XML を使い分ける -さらに、HTMLを返す独自の Body Writer を作る *複数のフォーマットに対応した JAX-RS [#xaa1d94e] -MyBean.java #code(java){{{ package com.mycompany.multiplereply; import java.io.Serializable; import javax.xml.bind.annotation.XmlRootElement; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor @XmlRootElement public class MyBean implements Serializable { private String name; private String sex; private int age; public MyBean() { super(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(String.format("<h1>%s</h1>", name)); sb.append("<ul>"); sb.append(String.format("<li>SEX: %s</li>", sex)); sb.append(String.format("<li>AGE: %d</li>", age)); sb.append("</ul>"); return sb.toString(); } } }}} -HelloResource.java #code(java){{{ package com.mycompany.multiplereply; import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import javax.ws.rs.Produces; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; @Path("generic") public class HelloResource { @Context private UriInfo context; public HelloResource() { } @GET @Path("hello") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_HTML}) public MyBean getSomeFormat() { return new MyBean("Sachi","female",32); } } }}} --@Produces に、複数のフォーマットを指定すれば、HTTP Request の Accept Header に従って、適切なフォーマットで MyBean が返却される --MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML は、Glassfish (Jersey) が勝手にやってくれる --MediaType.TEXT_HTML は自分で何とかしなきゃいけない。[[後述>#html]] *クライアント [#qcf3895b] -html #ref(hyper-0.png) #code(html){{{ <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <title>Start Page</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <h1>Hello World!</h1> <button id="btnJson">JSON</button> <button id="btnXml">XML</button> <button id="btnHtml">HTML</button><br/> <textarea cols="80" rows="5"></textarea> <div></div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ $('#btnJson').on('click', function(){ var args = { }; var url = 'webresources/generic/hello'; $.getJSON(url, args, function(data){ $('textarea').text(JSON.stringify(data)); }); }); $('#btnXml').on('click', function(){ var url = 'webresources/generic/hello'; $.ajax({ url : url, dataType : 'xml' }).done(function(data){ console.log(data); $('textarea').text((new XMLSerializer()).serializeToString(data)); }); }); $('#btnHtml').on('click', function(){ var url = 'webresources/generic/hello'; $.ajax({ url : url, dataType : 'html' }).done(function(data){ console.log(data); $('textarea').text(data); $('div').append(data); }); }); }); </script> </body> </html> }}} -Request JSON&br; &ref(hyper-1.png); &ref(hyper-4.png); -Request XML&br; &ref(hyper-2.png); &ref(hyper-5.png); -Request HTML&br; &ref(hyper-3.png); &ref(hyper-6.png); *&aname(html){JSON,XML 以外の形式でデータを返す}; [#sdb78371] -MyMessageBodyWriter.java #code(java){{{ package com.mycompany.multiplereply; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; @Provider @Produces(MediaType.TEXT_HTML) public class MyBeanDomWrite implements MessageBodyWriter<MyBean> { @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == MyBean.class; } @Override public long getSize(MyBean t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { // -1 means unknown return -1; } @Override public void writeTo(MyBean t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { PrintWriter out = new PrintWriter(entityStream); out.print(t); out.close(); } } }}} --MessageBodyWriter インタフェースの実装クラスを作成して、@Provider アノテーションを付与する --@Produces で、対応するフォーマット名を指定する --後は上記の通り -ApplicationConfig.java にも登録する必要あり (NetBeans が勝手にやってくれる) #code(java){{{ package com.mycompany.multiplereply; import java.util.Set; import javax.ws.rs.core.Application; /** * * @author hondou */ @javax.ws.rs.ApplicationPath("webresources") public class ApplicationConfig extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> resources = new java.util.HashSet<Class<?>>(); // following code can be used to customize Jersey 1.x JSON provider: try { Class jacksonProvider = Class.forName("org.codehaus.jackson.jaxrs.JacksonJsonProvider"); resources.add(jacksonProvider); } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null, ex); } addRestResourceClasses(resources); return resources; } /** * Do not modify addRestResourceClasses() method. * It is automatically populated with * all resources defined in the project. * If required, comment out calling this method in getClasses(). */ private void addRestResourceClasses(Set<Class<?>> resources) { resources.add(com.mycompany.multiplereply.HelloResource.class); resources.add(com.mycompany.multiplereply.MyBeanDomWrite.class); } } }}} -入力で特殊なフォーマットを使いたい場合には MessageBodyWriter。ただ、入力の方は、あんまり奇抜なことはやらずに、素直に FORM SUBMIT か JSON か XML にすりゃいいんだけどね -入力で特殊なフォーマットを使いたい場合には MessageBodyReader。ただ、入力の方は、あんまり奇抜なことはやらずに、素直に FORM SUBMIT か JSON か XML にすりゃいいんだけどね ---- [[Java#Glassfish]]