本文将介绍Golang(11)WebService-RESTful的详细情况,。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Golang建立RESTfulw
本文将介绍Golang(11)Web Service - RESTful的详细情况,。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Golang 建立RESTful webservice 接收客户端POST请求发送wav语音文件、java – SOAP webservice和RESTFUL webservice之间的区别、JSR311发布Restful WebService工程、JSR311让Restful WebService变简单的知识。
本文目录一览:- Golang(11)Web Service - RESTful
- Golang 建立RESTful webservice 接收客户端POST请求发送wav语音文件
- java – SOAP webservice和RESTFUL webservice之间的区别
- JSR311发布Restful WebService工程
- JSR311让Restful WebService变简单
Golang(11)Web Service - RESTful
Golang(11)Web Service - RESTful
1. Concept
Requests can be matched based on URL host,path,path prefix,schemes,header and query values,HTTP methods or using custom matchers.
URL hosts and paths can have variables with an optional regular expression.
It implements the http.Handler interface so it is compatible with the standard http.ServeMux.
router := mux.NewRouter()
router.HandleFunc("/",HomeHandler)
router.HandleFunc("/products",ProductsHandler)
Once the router matches,the handler will be called passing (http.ResponseWriter,http.Requet)as parameters.
Variables in paths follow this pattern,{name} or {name:pattern}.
router.HandleFunc(“/products/{key}”,ProductHandler)
router.HandleFunc(“/articles/{category}/{id:[0-9]+}”,ArticleHandler)
We can fetch all these values from map
vars :=mux.Vars(request)
category := vars[“category"]
Some other matches
router.Host(“www.domain.com”)
router.Host(“{subdomain:[a-z]+}.domain.com”)
router.PathPrefix(“/products/“)
router.Methods(“GET”,“POST”)
router.Schemes(“https”)
router.Headers(“X-Requested-With”,“XMLHttpRequest”)
router.Queries(“key”,“value”)
Example:
router.HandleFunc(“/products”,ProductsHandler).Host(“www.domain.com”).Methods(“GET”).Schemes(“http”)
Work with Sub Router
router := mux.NewRouter()
sub := router.Host(“www.domain.com”).Subrouter()
sub.HandleFunc(“/products/“,ProductsHandler)
Name a Router and Build the URL
router := mux.NewRouter()
router.HandleFunc(“/articles/{category}/{id:[0-9]+}”,ArticleHandler).Name(“article”)
url,err := r.Get(“article”).URL(“category”,“technology”,“id”,“42”)
eg: “/articles/technology/42"
2. Installation
>go get github.com/gorilla/mux
Here is the Whole go implementation Class as follow:
package main
import (
"encoding/json” //import the json package to marshal and unmarshal JSON
"fmt"
"github.com/gorilla/mux” //here is the router and dispatcher
"io/IoUtil” //io util to read/write to io
"net/http” //handle the http based request and response
)
type Bug struct { //my demo object in go
Id string
BugNumber string
BugName string
BugDesn string
}
type BugResult struct { //my common REST response object
Bugs []Bug
Status string
}
func getBug(w http.ResponseWriter,r *http.Request) { //get method
b1 := Bug{Id: "1",BugNumber: "bug1",BugName: "bug1",BugDesn: "desn1"}
re := BugResult{Status: "Ok",Bugs: []Bug{b1}}
b,err := json.Marshal(re) //marshal the object to JSON
if err != nil {
fmt.Fprint(w,"json err: %s",err)
}
fmt.Fprint(w,string(b)) //write to the response
}
func updateBug(w http.ResponseWriter,r *http.Request) {
var b Bug
c,err := IoUtil.ReadAll(r.Body) //read the string from body and unmarshal
fmt.Println("updateBug called with Body=" + string(c))
json.Unmarshal(c,&b)
fmt.Println("updateBug called with Id=" + b.Id)
fmt.Println("updateBug called with BugNumber=" + b.BugNumber)
fmt.Println("updateBug called with BugName=" + b.BugName)
fmt.Println("updateBug called with BugDesn=" + b.BugDesn)
re := BugResult{Status: "OK",Bugs: []Bug{b}}
re_json,err := json.Marshal(re)
if err != nil {
fmt.Fprint(w,string(re_json))
}
func deleteBug(w http.ResponseWriter,r *http.Request) {
id := mux.Vars(r)["Id”] //get the param from Path
fmt.Println("deleteBug called with Id = ",id)
re := BugResult{Status: "OK"}
b,string(b))
}
func addBug(w http.ResponseWriter,r *http.Request) {
var b Bug
content,err := IoUtil.ReadAll(r.Body)
fmt.Println("addBug called with Body=" + string(content))
json.Unmarshal(content,&b)
fmt.Println("addBug called with BugNumber=" + b.BugNumber)
fmt.Println("addBug called with BugName=" + b.BugName)
fmt.Println("addBug called with BugDesn=" + b.BugDesn)
re := BugResult{Status: "OK",string(re_json))
}
func listBug(w http.ResponseWriter,r *http.Request) {
b1 := Bug{Id: "1",BugDesn: "desn1"}
b2 := Bug{Id: "2",BugNumber: "bug2",BugName: "bug2",BugDesn: "desn2"}
re := BugResult{Status: "Ok",Bugs: []Bug{b1,b2}}
b,string(b))
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/bugs",listBug).Methods("GET")
router.HandleFunc("/bugs",addBug).Methods("POST")
router.HandleFunc("/bugs/{Id}",getBug).Methods("GET")
router.HandleFunc("/bugs/{Id}",updateBug).Methods("PUT")
router.HandleFunc("/bugs/{Id}",deleteBug).Methods("DELETE")
http.Handle("/",router)
http.ListenAndServe(":8088",nil)
}
It is not very nice since there is repeat codes like this.
b,string(b))
I will check how to avoid that.
References:
https://github.com/drone/routes
https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/08.3.md
https://github.com/gorilla/mux
http://www.gorillatoolkit.org/pkg/mux
JSON handle
http://sillycat.iteye.com/blog/2065585
Golang 建立RESTful webservice 接收客户端POST请求发送wav语音文件
首先看下服务器端,服务器端使用martini框架,仅建立一个简单的接收客户端post请求并保存客户端传过来的语音的后台服务:
原文地址:http://www.jb51.cc/article/p-tonyjcqq-hg.html
package main //http://liuxp0827.blog.51cto.com/5013343/1412977 import ( "bufio" "github.com/go-martini/martini" "io/IoUtil" "log" "net/http" "os" ) func main() { m := martini.Classic() m.Post("/wave",func(req *http.Request) { file,_,err := req.FormFile("file") if err != nil { log.Fatal("FormFile: ",err.Error()) os.Exit(2) } defer func() { if err := file.Close(); err != nil { log.Fatal("Close: ",err.Error()) os.Exit(2) } }() localFile,_ := os.Create("1.wav") defer localFile.Close() writer := bufio.NewWriter(localFile) bytes,err := IoUtil.ReadAll(file) if err != nil { log.Fatal("ReadAll: ",err.Error()) os.Exit(2) } writer.Write(bytes) writer.Flush() }) http.ListenAndServe(":8080",m) }
再来看下客户端的java代码,首先调用readWavform函数从本地读取语音文件到byte[],然后设置相应的POST头信息,最终发送数据:
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; //http://liuxp0827.blog.51cto.com/5013343/1412977 public final class upload { public static void main(String[] args) { Map<String,String> parameters = new HashMap<String,String>(); byte[] data = readWavform("C:\\Users\\PONPON\\Desktop\\test.wav"); doUploadFile("http://localhost:8080/wave",parameters,Constants.FILEParaM,"11.wav","multipart/form-data;",data); } public static byte[] readWavform(String filename) { int regLen = 0; byte[] regbuffer = null; try { FileInputStream inputsteam = new FileInputStream(new File(filename)); regLen = inputsteam.available(); regbuffer = new byte[regLen]; if ((regLen = inputsteam.read(regbuffer,regLen)) < 0) { System.out.println("error when read pcm file."); } } catch (FileNotFoundException e) { // Todo Auto-generated catch block e.printstacktrace(); } catch (IOException e) { // Todo Auto-generated catch block e.printstacktrace(); } return regbuffer; } public static String doUploadFile(String reqUrl,Map<String,String> parameters,String fileParamName,String filename,String contentType,byte[] data) { HttpURLConnection urlConn = null; try { urlConn = sendFormdata(reqUrl,fileParamName,filename,contentType,data); String responseContent = new String(getBytes(urlConn)); return responseContent.trim(); } catch (Exception e) { throw new RuntimeException(e.getMessage(),e); } finally { if (urlConn != null) { urlConn.disconnect(); } } } private static HttpURLConnection sendFormdata(String reqUrl,byte[] data) { HttpURLConnection urlConn = null; try { URL url = new URL(reqUrl); urlConn = (HttpURLConnection) url.openConnection(); urlConn.setRequestMethod("POST"); urlConn.setConnectTimeout(10000);// (单位:毫秒)jdk urlConn.setReadTimeout(10000);// (单位:毫秒)jdk 1.5换成这个,读操作超时 urlConn.setDoOutput(true); urlConn.setRequestProperty("connection","keep-alive"); String boundary = "-----------------------------114975832116442893661388290519"; // 分隔符 urlConn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + boundary); boundary = "--" + boundary; StringBuffer params = new StringBuffer(); if (parameters != null) { for (Iterator<String> iter = parameters.keySet().iterator(); iter .hasNext();) { String name = iter.next(); String value = parameters.get(name); params.append(boundary + "\r\n"); params.append("Content-disposition: form-data; name=\"" + name + "\"\r\n\r\n"); params.append(value); params.append("\r\n"); } } StringBuilder sb = new StringBuilder(); sb.append(boundary); sb.append("\r\n"); sb.append("Content-disposition: form-data; name=\"" + fileParamName + "\"; filename=\"" + filename + "\"\r\n"); sb.append("Content-Type: " + contentType + "\r\n\r\n"); byte[] fileDiv = sb.toString().getBytes("UTF-8"); byte[] endData = ("\r\n" + boundary + "--\r\n").getBytes("UTF-8"); byte[] ps = params.toString().getBytes("UTF-8"); OutputStream os = urlConn.getoutputStream(); os.write(ps); os.write(fileDiv); os.write(data); os.write(endData); os.flush(); os.close(); } catch (Exception e) { throw new RuntimeException(e.getMessage(),e); } return urlConn; } private static byte[] getBytes(HttpURLConnection urlConn) { try { InputStream in = urlConn.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; for (int i = 0; (i = in.read(buf)) > 0;) os.write(buf,i); in.close(); return os.toByteArray(); } catch (Exception e) { throw new RuntimeException(e.getMessage(),e); } } }
这只是简单的功能实现,后面可以用martini拓展,写一个简单的web语音识别服务,用android录音后发送POST请求,把语音数据发送到服务器处理识别,再返回json格式的识别结果。
java – SOAP webservice和RESTFUL webservice之间的区别
> SOAP Webservice.
> RESTful Webservice.
任何人都可以告诉我它们之间的基本区别是什么.在哪种情况下创建SOAP Web服务以及在哪种情况下创建RESTful Webservice.
谢谢,
解决方法
肥皂:
>您在.wsdl文件中定义接口,该文件准确描述了预期的输入参数以及返回值的外观
>有些工具可以用java类hirarchies生成.wsdl文件. JAXB for example
>还有一些工具可以生成java对象/类作为eclipse的一部分(例如暂时不知道名称).
> SOAP非常严格.在处理之前,每个请求都是针对wsdl进行验证的.
从SOAP WS框架开始,一个好但不那么容易的是Apache CXF
REST(到目前为止没有亲身体验,随时纠正和改进;)):
>访问Web服务器或Web应用程序以从中检索数据或向其发送数据的方法.
>它只是协商,如何访问.
> common就是这个http://server.domain.com/app/type/id=123,用于检索id = 123的类型类型的对象
>非常直观,但没有自动验证请求.
> ……
我相信,我错过了其他几点.但我认为这是一个有用的开始.
JSR311发布Restful WebService工程
背景知识
Representational state transfer (REST) Web Service:
它是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。在目前三种主流的Web Service实现方案中,因为REST与SOAP和XML-RPC相比显的更加简洁,因此越来越多的Web Service开始采用REST风格设计和实现。
参考资料:http://en.wikipedia.org/wiki/Representational_State_Transfer
Jersey:
它是Sun对JSR311的官方参考实现,而JSR311是java中实现Restful Web Service的API规范(JSR311: JAX-RS: The Java API for RESTful Web Services)。JSR311有一个重要目标:使用注解(annotation)把POJO暴露成Web Service,这样就比较轻量级。
参考资料:https://jsr311.dev.java.net/nonav/releases/1.0/spec/index.html
Grizzly:
Grizzly于2004年诞生在GlassFish中,开始目的是要建构一个HTTP Web服务器,用来代替Tomcat的Coyote连接器和Sun WebServ er6.1。后来,Grizzly成为一种应用程序框架,专门解决编写成千上万用户访问服务器时候产生的各种问题。使用JAVA NIO作为基础,并隐藏其编程的复杂性。在本例中,我们将其用作内嵌的Servlet Container。
参考资料:https://grizzly.dev.java.net/
准备工作
首先,下载grizzly和jersey。其中,grizzly的下载地址为:http://download.java.net/maven/2/com/sun/grizzly/grizzly-servlet-webserver/1.9.18a/grizzly-servlet-webserver-1.9.18a.jar,jersey的下载地址为:http://download.java.net/maven/2/com/sun/jersey/jersey-archive/1.1.2-ea/jersey-archive-1.1.2-ea.zip
在Eclipse中建一个Java工程,名为jsr331,然后把下载的jersey-archive-1.1.2-ea.zip解压,将jersey-archive-1.1.2-ea/contribs、jersey-archive-1.1.2-ea/lib两个目录下的jar包,连同下载的grizzly-http-webserver-1.9.18a.jar都拷贝到jsr331工程下的lib目录,并加入到该工程的Build Path。(实测中,发现还需要引入一个包,下载地址:http://repository.jboss.org/maven2/org/jvnet/mimepull/1.2/mimepull-1.2.jar)
编写最简单的服务
JSR331把准备提供Web Service的类称为Resource class。Resource class是一个普通类(POJO),但是按照规范要求增加了特定的注解(annotation)。我们首先实现最简单的hello world服务。
在jinxfei.test.jsr311.service下,建立HelloService类,内容如下:
- package jinxfei.test.jsr311.service;
- import javax.ws.rs.GET;
- import javax.ws.rs.Path;
- import javax.ws.rs.Produces;
- @Path("/hello")
- public class HelloService {
- @GET
- @Produces("text/plain")
- public String helloWorld(){
- return "Hello world!";
- }
- }
代码中的注解(annotation)决定了程序发布成Web Service后的行为和特性。其中,HelloService类前面的@PATH,表明该Service的URL路径,这种类名前面带@PATH注解的类被称为Root Resource Class,因为他们决定了访问Service时URI中的第一级路径;@GET表示访问该服务使用HTTP GET方法;@Produces规定该服务返回结果的类型,这里的”text/plain”表名返回纯文本。
发布服务
实现服务类后,我们要启动一个内嵌的grizzly servlet container,并把HelloService发布到该Container中,这样就能通过HTTP协议访问该服务。Jersey提供了两种发布方式,标准的做法需要在web.xml中做配置,所以比较适用于部署在独立的Web Container下的应用,本文不做深入介绍,可参见:http://docs.sun.com/app/docs/doc/820-4867/6nga7f5o4?l=en&a=view。本例与grizzly整合,所以使用grizzly的工具类,通过代码进行部署配置。
在jinxfei.test.jsr311包下创建ServiceDeployer类,内容如下:
copy
JSR311让Restful WebService变简单
需求
公司有一个产品,包括前台WEB界面和多个后台服务,各个服务都需要在前面界面中进行配置和控制,以调整服务的行为。以前,配置文件都存放在数据库中,界面上修改配置后入库,并发送消息(Socket)通知特定的服务重新加载配置。这样有些问题,一方面自己维护Socket带来很多麻烦,二来数据库重建的时候,需要备份/恢复这些配置数据。
所以,我们想把配置文件局部化到各个服务(比如用本地文件存储),然后在界面上修改的时候,实时向服务请求当前配置数据(XML格式),修改完毕后,再直接发给服务进行更新和存储。而在通信方式上,我们希望各个服务提供Web Service接口来实现配置的检索和更新。
但Web Service通常需要在Web Container(比如,tomcat,jboss)中实现,而我们不想把所有的服务都跑在tomcat里,于是想找到一种更加轻量级的方式。
今天偶然看到JSR311,进而发现在Java后台服务中内嵌grizzly(基于NIO的实现)和Jersey(Sun的JSR311参考实现)来提供Restful Web Service能力,是非常方便的。个人认为这种方式适用于后台Java程序的控制、配置和监视,其作用有些类似于JMX,但比实现JMX要简单的多(JSR311基于POJO)。
背景知识
Representational state transfer (REST) Web Service:
它是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。在目前三种主流的Web Service实现方案中,因为REST与SOAP和XML-RPC相比显的更加简洁,因此越来越多的Web Service开始采用REST风格设计和实现。
参考资料:http://en.wikipedia.org/wiki/Representational_State_Transfer
Jersey:
它是Sun对JSR311的官方参考实现,而JSR311是java中实现Restful Web Service的API规范(JSR311: JAX-RS: The Java API for RESTful Web Services)。JSR311有一个重要目标:使用注解(annotation)把POJO暴露成Web Service,这样就比较轻量级。
参考资料:https://jsr311.dev.java.net/nonav/releases/1.0/spec/index.html
Grizzly:
Grizzly于2004年诞生在GlassFish中,开始目的是要建构一个HTTP Web服务器,用来代替Tomcat的Coyote连接器和Sun WebServ er6.1。后来,Grizzly成为一种应用程序框架,专门解决编写成千上万用户访问服务器时候产生的各种问题。使用JAVA NIO作为基础,并隐藏其编程的复杂性。在本例中,我们将其用作内嵌的Servlet Container。
参考资料:https://grizzly.dev.java.net/
准备工作
首先,下载grizzly和jersey。其中,grizzly的下载地址为:http://download.java.net/maven/2/com/sun/grizzly/grizzly-servlet-webserver/1.9.18a/grizzly-servlet-webserver-1.9.18a.jar,jersey的下载地址为:http://download.java.net/maven/2/com/sun/jersey/jersey-archive/1.1.2-ea/jersey-archive-1.1.2-ea.zip
在Eclipse中建一个Java工程,名为jsr331,然后把下载的jersey-archive-1.1.2-ea.zip解压,将jersey-archive-1.1.2-ea/contribs、jersey-archive-1.1.2-ea/lib两个目录下的jar包,连同下载的grizzly-http-webserver-1.9.18a.jar都拷贝到jsr331工程下的lib目录,并加入到该工程的Build Path。(实测中,发现还需要引入一个包,下载地址:http://repository.jboss.org/maven2/org/jvnet/mimepull/1.2/mimepull-1.2.jar)
编写最简单的服务
JSR331把准备提供Web Service的类称为Resource class。Resource class是一个普通类(POJO),但是按照规范要求增加了特定的注解(annotation)。我们首先实现最简单的hello world服务。
在jinxfei.test.jsr311.service下,建立HelloService类,内容如下:
- package jinxfei.test.jsr311.service;
- import javax.ws.rs.GET;
- import javax.ws.rs.Path;
- import javax.ws.rs.Produces;
- @Path("/hello")
- public class HelloService {
- @GET
- @Produces("text/plain")
- public String helloWorld(){
- return "Hello world!";
- }
- }
代码中的注解(annotation)决定了程序发布成Web Service后的行为和特性。其中,HelloService类前面的@PATH,表明该Service的URL路径,这种类名前面带@PATH注解的类被称为Root Resource Class,因为他们决定了访问Service时URI中的第一级路径;@GET表示访问该服务使用HTTP GET方法;@Produces规定该服务返回结果的类型,这里的”text/plain”表名返回纯文本。
发布服务
实现服务类后,我们要启动一个内嵌的grizzly servlet container,并把HelloService发布到该Container中,这样就能通过HTTP协议访问该服务。Jersey提供了两种发布方式,标准的做法需要在web.xml中做配置,所以比较适用于部署在独立的Web Container下的应用,本文不做深入介绍,可参见:http://docs.sun.com/app/docs/doc/820-4867/6nga7f5o4?l=en&a=view。本例与grizzly整合,所以使用grizzly的工具类,通过代码进行部署配置。
在jinxfei.test.jsr311包下创建ServiceDeployer类,内容如下:
- package jinxfei.test.jsr311;
- import java.io.IOException;
- import java.net.URI;
- import java.util.HashMap;
- import java.util.Map;
- import javax.ws.rs.core.UriBuilder;
- import com.sun.grizzly.http.SelectorThread;
- import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;
- public class ServiceDeployer {
- public static void main(String[] args) throws IOException {
- URI ServerURI=UriBuilder.fromUri("http://localhost/").port(9876).build();
- startServer(ServerURI);
- System.out.println("服务已启动,请访问:"+ServerURI);
- }
- protected static SelectorThread startServer(URI serverURI) throws IOException {
- final Map<String, String> initParams = new HashMap<String, String>();
- initParams.put("com.sun.jersey.config.property.packages","jinxfei.test.jsr311.service");
- System.out.println("Grizzly 启动中...");
- SelectorThread threadSelector = GrizzlyWebContainerFactory.create(serverURI, initParams);
- return threadSelector;
- }
- }
在Eclipse中运行该类,控制台上打印“服务已启动”字样,表示系统启动成功,打开浏览器,输入:http://localhost:9876/hello,即可看到效果,如下图所示:
让功能再强一点点
接下来,我们要让服务能够接受参数,并根据参数打印不同的信息,最简单的就是回显(Echo)。为了实现这一功能,我们给HelloService类增加一个方法:
- @POST @Path("echo")
- @Consumes("application/x-www-form-urlencoded")
- public String echo(@FormParam("msg") String message){
- return "Are you saying:"+message;
- }
@POST表明该方法要用HTTP Post来访问,@Path表明访问该方法的相对路径是echo,@Consumes表明该方法处理HTTP Post请求中何种类型的数据。该方法参数中的注解@FormParam("msg")说明后面的“String message”参数取自表单提交数据中的msg。
由于该方法需要Post访问,且需要通过表单提交数据,所以我们创建一个test.htm,在其中写一个简单的Form:
- <form action="http://localhost:9876/hello/echo" method="post">
- <input type="text" name="msg">
- <input type="submit" value="submit">
- </form>
重启ServiceDeployer,然后在浏览器中打开test.htm,表单中输入任意信息:
然后点提交按钮,可以看到如下信息:
这说明HelloService已经提取了表单参数,并回显给用户。
深入学习
请参考官方资料:
JSR311规范:https://jsr311.dev.java.net/nonav/releases/1.0/spec/index.html
JSR311参考实现的主要特性:http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features
关于Golang(11)Web Service - RESTful的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Golang 建立RESTful webservice 接收客户端POST请求发送wav语音文件、java – SOAP webservice和RESTFUL webservice之间的区别、JSR311发布Restful WebService工程、JSR311让Restful WebService变简单的相关信息,请在本站寻找。
本文标签: