前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分布式开发、基于Restful的WEB服务如何实现?

分布式开发、基于Restful的WEB服务如何实现?

作者头像
爱明依
发布2019-03-12 14:59:56
5640
发布2019-03-12 14:59:56
举报
文章被收录于专栏:爱明依爱明依

1、课程名称:基于Restful的WEB服务实现

2、课程内容

那么既然说到了分布式的开发,那么所有的开发者一定都会立刻联想到一个词:“慢”,对于传统的WEB服务开发(AXIS、XFire、CXF等),而且在编写的时候需要编写一大堆的客户端代码,这样对于整个程序的开发的复杂度还是非常高的,可是在实际的开发之中,如果你作为一个架构师,一定不可能将你一个项目的所有的子系统都设计为一个,中间一定会拆分成若干个子系统,于是这个若干个子系统之间如果要想进行数据的交互处理,只能够使用RPC。

在整个系统的处理过程里面,对于Restful的实现要比传统的任何的WEB服务的操作都方便。所有的处理都是以资源路径的形式出现的,回顾一下,如果现在使用的是普通开发架构:

现在我的所有资源都保存在了“/pages/back/message”,则此时对于路径可能就分为:

· 增加路径:/pages/back/message/add.action;

· 修改路径:/pages/back/message/edit.action;

· 删除路径:/pages/back/message/rm.action;

· 修改路径:/pages/back/message/list.action;

如果基于Restful风格,那么对于路径操作就没有必要如此的复杂:

· 增加数据:POST请求模式,使用“/message”;

· 修改数据:PUT请求模式,使用“/message”;

2.1、使用jesey开发Restful服务

如果要想开发Restful架构的WEB服务,那么需要使用jesey组件。这个组件主要实现WEB Service的开发模式。在这个组件里面整合了JAXB操作标准,可以自动的将VO类对象转换为JSON或者是XML结构。

1、 建立一个新的WEB项目:RestProject;

· 由于此时还没有整合Spring,所以建立项目的时候一定要建立好web.xml文件;

2、 将jesey的开发包设置到项目之中;

· 版本:jersey-archive-1.19.1.zip。

3、 在web.xml文件里面追加如下的配置信息,主要是为了接收WEB服务使用的;

· 处理的Servlet:com.sun.jersey.spi.container.servlet.ServletContainer

<servlet> <servlet-name>restService</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>cn.mldn.resources</param-value>  </init-param> </servlet> <servlet-mapping> <servlet-name>restService</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping>

Restful风格实现的WEB服务代码,都需要使用Annotation的方式来进行处理,所以一定要配置好扫描包;

4、 在cn.mldn.resources包中建立HelloResource程序,这个程序主要就是进行最简单的打印信息的操作;

package cn.mldn.resources; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/hello") public class HelloResource { @GET @Produces(MediaType.TEXT_PLAIN)  public String say() { return "www.mldn.cn" ; } }

在整个的开发过程之中,程序的编写几乎没有任何的难点,包括如下几个说明:

· “@Path("/hello")”:表示此服务的访问路径;

· “@GET”:表示此服务的路径将基于GET请求的模式来进行处理;

· “@Produces(MediaType.TEXT_PLAIN)”:表示的响应的结果,以文本的方式返回。

5、 将项目发布到Tomcat之中;

· 路径:http://localhost/RestProject/rest/hello

整个这样的方式所实现的WEB服务不仅简单而且性能要高。

2.2、jesey开发深入

如果要是实现基于Restful架构风格的WEB服务,那么对于接收与返回的数据重点在于JSON结构上,也就是说只有返回的类型为JSON才可以被所有的操作所正常解析。

所以本次将使用JAXB实现VO与JSON的转换处理操作。

1、 定义一个MessageResource程序类;

package cn.mldn.resources; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/message") public class MessageResource { @GET @Path("/json") @Produces(MediaType.APPLICATION_JSON) public String getJson() { return "{mid:10,title:'Java开发'}" ; } }

但是以上的实现操作之中都是基于字符串的过程,这样在很大程度上来讲并不方便。最好的做法是利用VO类转换。

2、 定义Message.java类

package cn.mldn.vo; import java.io.Serializable; import javax.xml.bind.annotation.XmlRootElement; @SuppressWarnings("serial") @XmlRootElement  public class Message implements Serializable { private Integer mid ; private String title ; public Integer getMid() { return mid; } public void setMid(Integer mid) { this.mid = mid; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }

如果需要将VO对象自动转换为JSON结构,那么一定要使用“@XmlRootElement”注解操作。

但是千万要记住一点,此时如果要是存在有级联关系(一般别这么写),那么就必须针对于级联设置元素名称。

package cn.mldn.vo; public class Member { private String name ; private Integer age ; }

随后在资源里面对其进行定义:

@GET  @Path("/list") @Produces(MediaType.APPLICATION_JSON) public Message getList() { Message vo = new Message() ; vo.setMid(10); vo.setTitle("Java开发"); vo.setMembers(new ArrayList<Member>()); for (int x = 0 ; x < 10 ; x ++) { Member mem = new Member() ; mem.setName("mldn - " + x); mem.setAge(x); vo.getMembers().add(mem) ; } return vo ; }

这个时候在进行数据输出操作中,如果不想使用默认的属性名称作为数组的名称,那么可以直接在Message类中进行定义:

@XmlElement(name="allMessages")  public List<Member> getMembers() { return members; }

随后在生成数据的时候就会自动的使用“allMessages”作为所有Message的数组的key的信息。

在Jesey里面是可以注入一些操作对象的,使用“@Context”注解即可。

范例:注入对象

@Context private Request request ; @Context private UriInfo uriInfo ; @Context private ServletContext context ; @GET  @Path("/info") @Produces(MediaType.TEXT_PLAIN) public String info() { System.out.println("REQUEST : " + this.request.getMethod()); System.out.println("UriInfo : " + this.uriInfo.getPath()); System.out.println("ServletContext : " + this.context.getRealPath("/")); return "www.mldn.cn" ; }

REQUEST : GET UriInfo : message/info ServletContext : C:\apache-tomcat-8.0.36\webapps\RestProject\

在整个Restful架构的处理过程之中,依然可以与所使用的容器结合在一起使用。

2.3、设置请求参数

在Restful风格的架构里面对于参数的接收有许多的方式,而且使用Restful实现的WEB服务架构最大的好处在于其可以直接以WEB的方式运行。

2.3.1、@QueryParam

可以接收以地址重写的方式传递的参数内容。

1、 定义Echo操作:

package cn.mldn.resources; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/myparam") public class ParamResource { @GET @Path("echo") @Produces(MediaType.TEXT_PLAIN)  public String echo(@QueryParam("msg") String msg) { return "ECHO : " + msg ; } }

随后运行的时候要使用地址重写的方式传递:

· 地址:http://localhost/RestProject/rest/myparam/echo?msg=mldn

2.3.2、@FormParam

此注解表示参数是通过表单设置完成的。

范例:定义一个使用“@FormParam”接收的参数方法

@POST @Path("show") @Produces(MediaType.TEXT_PLAIN) public String show(@FormParam("info") String info) { return "[Echo] : " + info ; }

既然此处使用的是表单提交的方式处理,所以使用POST请求模式完成。

范例:定义表单

<form action="<%=basePath%>rest/myparam/show" method="post"> 消息:<input type="text" name="info" id="info"> <input type="submit" value="提交"> </form>

只要是表单提交的操作处理,都建议使用此种模式完成。

2.3.3、@PathParam

“@PathParam”对于它的使用环境比较多,而且如果需要传递多个参数,也一定要使用“@PathParam”完成。

1、 直接以路径的形式设置内容:

@GET @Path("/{msg}")  @Produces(MediaType.TEXT_PLAIN) public String msg(@PathParam("msg") String msg) { return "ECHO : " + msg ; }

访问地址:http://localhost/RestProject/rest/myparam/mldn/

2、 传递多个参数:

对于多个参数的传递的处理操作,可以直接利用PathSegment完成,但是它也是基于PathParam的方式处理的,并且最为重要的是所有的参数之间使用“;”分割。

范例:使用PathSegment来进行参数接收

@GET @Path("/query/{condition}") @Produces(MediaType.TEXT_PLAIN) public String segment(@PathParam("condition") PathSegment condition) { System.out.println("*******************" + condition.getPath());   MultivaluedMap<String, String> map = condition.getMatrixParameters() ; Iterator<Map.Entry<String,List<String>>> iter = map.entrySet().iterator() ; while (iter.hasNext()) { Map.Entry<String,List<String>> me = iter.next() ; System.out.println("key = " + me.getKey() + "、value = " + me.getValue()); }  return "mldn" ; }

*******************restful-mldn key = cp、value = [1] key = ls、value = [10] key = type、value = [1,2,3]

访问路径:http://localhost/RestProject/rest/myparam/query/restful-mldn;cp=1;ls=10;type=1,2,3

可以发现,所有的参数最终接收之后都变为了List集合的形式。

实际上在这里面操作的时候也存在有另外一种小小的注解,因为以上的操作是将所有的参数都设置在一起了,虽然可以进行传递,但是在进行取得内容的时候还是比较麻烦的。所以在Jesey里面提供有一个“@MatrixParam”注解分开接收。

范例:分开接收参数内容

@GET @Path("/more/{condition}") @Produces(MediaType.TEXT_PLAIN) public String msegment( @PathParam("condition") PathSegment condition , @MatrixParam("cp") int currentPage , @MatrixParam("ls") int lineSize) { System.out.println("*******************" + condition.getPath()); System.out.println("currentPage = " + currentPage); System.out.println("lineSize = " + lineSize); return "mldn" ; }

以上的操作在进行参数传递的时候依然可以正常接收:

· 路径:http://localhost/RestProject/rest/myparam/more/restful-mldn;cp=2;ls=100

在restful架构里面如果要传递的参数的结构较多,则也可以使用正则匹配参数路径。

范例:定义具体的参数接收

@GET @Path("{region:.+}/beijing/{district:\\w+}") @Produces(MediaType.TEXT_PLAIN) public String city( @PathParam("region") List<PathSegment> region , @PathParam("district") String district) { Iterator<PathSegment> iter = region.iterator() ; while (iter.hasNext()) { System.out.println("*** " + iter.next().getPath()); } System.out.println("### district = " + district); return "city" ; }

对于参数的传递前面可以随便写,但是如果要想触发本操作,那么必须有“beijing”;

· 路径:http://localhost/RestProject/rest/myparam/China/BeiJing/beijing/chaoyangqu

如果现在需要进行多层的内容接收,则对于后续的定义也应该使用“.+”的形式完成,同时使用List集合;

@GET @Path("{region:.+}/beijing/{district:.+}") @Produces(MediaType.TEXT_PLAIN) public String city( @PathParam("region") List<PathSegment> region , @PathParam("district") List<PathSegment> district) { System.out.println("*** region = " + region); System.out.println("### district = " + district); return "city" ; }

此时“/beijing”前后内容可以随便编写,多少级都没有关系;

· 地址:http://localhost/RestProject/rest/myparam/China/BeiJing/beijing/chaoyangqu/maquanying/ditie

之所以会提供这么多风格的参数的操作,主要还是为了进行资源的统一利用。也就是说希望一个路径可以按照最简短的方式实现最多的功能。

2.4、Spring整合Jesey

如果在实际的开发之中,即便是进行了WEB服务的开发,那么依然需要业务层处理,依然需要数据层的操作处理,而这些肯定是Spring的强项,所以必须要将jesey组件与Spring整合。

1、 为项目添加Spring开发支持;

2、 在web.xml文件里面一定要配置好jesey相关内容,而一旦增加了Spring之后,那么也会自动出现一个监听器;

3、 随后要修改applicationContext.xml文件,需要配置Annotation声明注入;

<context:annotation-config/> <context:component-scan base-package="cn.mldn"/>

4、 定义资源类:

package cn.mldn.resources; import java.util.ArrayList; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import cn.mldn.vo.Member; import cn.mldn.vo.Message; @Path("/mymsg") @Component // 表示Spring组件 // 表示每一次请求发生时,都会生成一个新的Jesey服务实例 @Scope("prototype") // WEB服务是不需要保存用户状态的 public class SpringMessage { @GET  @Path("/list") @Produces(MediaType.APPLICATION_JSON) public Message getList() { Message vo = new Message() ; vo.setMid(10); vo.setTitle("Java开发"); vo.setMembers(new ArrayList<Member>()); for (int x = 0 ; x < 10 ; x ++) { Member mem = new Member() ; mem.setName("mldn - " + x); mem.setAge(x); vo.getMembers().add(mem) ; } return vo ; } }

5、 启动服务器,来观察当前的服务接口是否可用;

· http://localhost/RestProject/rest/mymsg/list

6、 编写客户端,执行数据的取得:

package cn.mldn.test; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.WebResource; public class TestMsg { public static void main(String[] args) { Client client = Client.create() ; WebResource wr = client.resource("http://localhost/RestProject/rest/mymsg/list") ; System.out.println(wr.get(String.class));  } }

这个时候对于整个的WEB服务的编写与实现可以发现非常的容易理解。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年03月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、课程名称:基于Restful的WEB服务实现
  • 2、课程内容
    • 2.1、使用jesey开发Restful服务
      • 2.2、jesey开发深入
        • 2.3、设置请求参数
          • 2.3.1、@QueryParam
          • 2.3.2、@FormParam
          • 2.3.3、@PathParam
        • 2.4、Spring整合Jesey
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档