用Jersey为Android客户端开发Restful Web Service
平时在做Android客户端的时候经常要与服务器之间通信,客户端通过服务端提供的接口获取数据,然后再展示在客户端的界面上,作为Android开发者,我们平时更多的是关注客户端的开发,而对服务端开发的关注相对较少,但是如果我们要自己一个人设计并开发一套完整的系统,我们就必须同时具备客户端和服务端的开发知识,而且我认为同时掌握客户端和服务端的开发技术还是很有用处的,不仅有助于提升我们的架构知识和能力,而且还……你懂得!身边一些做WEB开发的朋友很多都说为客户端开发接口和单纯地做WEB项目并没有很大的区别,不管后台语言用的是JAVA,PHP,还是C#等,用这些语言为客户端开发接口的时候有很多相似之处,比如说服务端请求路径的分发以及请求处理方式等。这几天出于好奇,想为自己的客户端开发Web Service接口,所以就在网上搜集了一些资料,发现有很多WEB框架可以很轻松地为移动端开发服务器接口,比如说Spring MVC,CXF,AXIS,RESTEasy等等,但是我最终选用了Jersey来完成服务端的开发。
首先,我们来大致说一下Jersey是什么。按照Jersey官网(https://jersey.java.net/)的介绍,Jersey是在Java开发中,为了简化RESTful Web Service以及客户端开发而设计的一套开源的,标准的,很优秀的,使用起来非常方便的JAX-RS API(即Java API for RESTful Web Services),Jersey支持JAX-RS API,并且是JAX-RS (JSR 311 & JSR 339) 的参考实现,值得注意的是,Jersey不仅仅是JAX-RS的参考实现,同时,它在JAX-RS工具包的基础上做了大量的扩展,增加了许多额外的特性和工具,并且都提供了丰富的说明文档以便开发者进一步对Jessey进行扩展以满足自己的实际开发需求。
为了方便大家更好地理解JAX-RS和RESTful,在这里我对这两个名词稍加说明。
JAX-RS按照百度百科上面的说明,即Java API for RESTful Web Services,是一个Java 编程语言的应用程序接口,支持按照表述性状态转移(REST)架构风格创建Web服务。JAX-RS使用了Java SE5引入的Java标注来简化Web服务的客户端和服务端的开发和部署。JAX-RS提供了一些标注将一个资源类,一个POJO Java类,封装为Web资源。JAX-RS包含了一系列的标注,包括:




- package com.jerseyserver.service;
- import java.util.ArrayList;
- import java.util.HashMap;
- import javax.ws.rs.FormParam;
- import javax.ws.rs.GET;
- import javax.ws.rs.POST;
- import javax.ws.rs.Path;
- import javax.ws.rs.Produces;
- import javax.ws.rs.core.GenericEntity;
- import javax.ws.rs.core.MediaType;
- import javax.ws.rs.core.Response;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.jerseyserver.entity.ResponseDTO;
- import com.jerseyserver.entity.User;
- import com.jerseyserver.util.TextUtil;
- @Path("/restService")
- public class RestService {
- @POST
- @Path("/getUserText")
- @Produces(MediaType.TEXT_PLAIN)
- /**
- * 测试返回text文本媒体类型数据的方式
- * @return "Hello,World!"
- */
- public String getUserText() {
- return "Hello,World!";
- }
- @GET
- @Path("/getUserXml")
- @Produces(MediaType.APPLICATION_XML)
- /**
- * 测试返回xml媒体类型数据的方式
- * @return User object
- */
- public User getUserXml() {
- User user = new User();
- user.setName("snail");
- user.setAge("22");
- user.setSex("male");
- return user;
- }
- @GET
- @Path("/getUserJson")
- @Produces(MediaType.APPLICATION_JSON)
- /**
- * 测试返回json媒体类型数据的方式
- * @return User object
- */
- public User getUserJson() {
- User user = new User();
- user.setName("snail");
- user.setAge("22");
- user.setSex("male");
- return user;
- }
- @POST
- @Path("/getUserInfo")
- @Produces(MediaType.APPLICATION_JSON)
- /**
- * 测试带请求参数时返回json媒体类型数据的方式
- * @param username
- * @return
- */
- public User getUserInfo(@FormParam("username") String username) {
- if (username == null || "".equals(username)) {
- return null;
- }
- return getUserByName(username);
- }
- /**
- * 通过用户名获取用户
- * @param username
- * @return User object
- */
- private User getUserByName(String username) {
- HashMap<String, User> map = initAllUsers();
- return map.get(username);
- }
- /**
- * 获取所有用户的map
- * @return 所有用户的map
- */
- private HashMap<String, User> initAllUsers() {
- HashMap<String, User> map = new HashMap<>();
- User user1 = new User();
- user1.setName("Jack");
- user1.setPasswd("Jack");
- user1.setAge(18 + "");
- user1.setSex("男");
- map.put(user1.getName(), user1);
- User user2 = new User();
- user2.setName("Alice");
- user2.setPasswd("Alice");
- user2.setAge(18 + "");
- user2.setSex("女");
- map.put(user2.getName(), user2);
- User user3 = new User();
- user3.setName("Allen");
- user3.setPasswd("Allen");
- user3.setAge(20 + "");
- user3.setSex("女");
- map.put(user3.getName(), user3);
- return map;
- }
- @POST
- @Path("/login")
- @Produces(MediaType.APPLICATION_JSON)
- /**
- * 用户登录
- * @param username 用户名
- * @param password 密码
- * @return Response object
- */
- public Response login(@FormParam("username") String username, @FormParam("password") String password) {
- if (TextUtil.isEmpty(username) || TextUtil.isEmpty(password)) {
- return null;
- }
- User user = checkUser(username, password);
- if (user == null) {
- return null;
- }
- ObjectMapper mapper = new ObjectMapper();
- GenericEntity<String> payloadEntity;
- try {
- payloadEntity = new GenericEntity<String>(
- mapper.writeValueAsString(new ResponseDTO(200, "ok", user))) {
- };
- return Response.ok(payloadEntity).build();
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- return Response
- .ok(" {\"status\": 404,\n\"message\": \"error\",\n\"response\": \"\"}")
- .build();
- }
- }
- /**
- * 验证用户是否存在
- * @param username
- * @param password
- * @return User object
- */
- private User checkUser(String username, String password) {
- HashMap<String, User> map = initAllUsers();
- User user = map.get(username);
- if (user != null) {
- String passwd = user.getPasswd();
- if (password.equals(passwd)) {
- return user;
- }
- }
- return null;
- }
- @POST
- @Path("/getAllUsers")
- @Produces(MediaType.APPLICATION_JSON)
- /**
- * 获取所有用户的集合
- * @return Response object
- */
- public Response getAllUsers() {
- ArrayList<User> list = new ArrayList<User>();
- User user1 = new User();
- user1.setName("Jack");
- user1.setPasswd("Jack");
- user1.setAge(18 + "");
- user1.setSex("男");
- list.add(user1);
- User user2 = new User();
- user2.setName("Alice");
- user2.setPasswd("Alice");
- user2.setAge(18 + "");
- user2.setSex("女");
- list.add(user2);
- User user3 = new User();
- user3.setName("Allen");
- user3.setPasswd("Allen");
- user3.setAge(20 + "");
- user3.setSex("女");
- list.add(user3);
- ObjectMapper mapper = new ObjectMapper();
- GenericEntity<String> payloadEntity;
- try {
- payloadEntity = new GenericEntity<String>(
- mapper.writeValueAsString(new ResponseDTO(200, "ok", list))) {
- };
- return Response.ok(payloadEntity).build();
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- return Response
- .ok(" {\"status\": 404,\n\"message\": \"error\",\n\"response\": \"\"}")
- .build();
- }
- }
- }
我们可以看到,类和接口方法均有注解,这些注解是必须写上去的,因为这些注解指定了一些很关键的信息,客户端请求的时候必须依赖这些注解才能最终找到请求的接口,然后通过接口获取数据并返回。RestService.java上面的注解@Path("/restService")指定了Web Service接口的转发路径,每一个接口方法上面有三个注解,其中,@POST和@GET等表示网络请求方式,请求方式除了@POST和@GET之外,常见的还有put、delete等;@Path("/getUserText")、@Path("/getUserXml")、@Path("/getUserJson")表示的是请求的接口的路径,与类的@Path注解和项目目录一起拼接组成完整的请求路径,@Path注解后面的名字可以按照命名规范自己取;@Produces指定了请求的数据格式,一般为JSON和XML,当然还有TEXT文档等类型。这些注解都指定好之后,那么客户端就可以通过完整的请求路径来访问服务器了,完整的路径格式为:http://[IP地址]:[端口号]/[服务端工程名]/[路径映射]/[接口类路径]/[接口方法路径],例如,客户端要访问我们项目中的login接口,那么客户端请求的完整路径为:http://192.168.254.26:8080/JerseyServer/rest/restService/login,192.168.254.26是我电脑的局域网IP地址,8080为访问apache的端口号,rest是在web.xml中配置的路径映射名。web.xml的配置内容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
- <web-app id="WebApp_ID">
- <!-- 同项目名 -->
- <display-name>JerseyServer</display-name>
- <servlet>
- <!-- 为servlet取名 -->
- <servlet-name>mobile</servlet-name>
- <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
- <init-param>
- <param-name>javax.ws.rs.Application</param-name>
- <!-- 配置自己的资源加载类,用于加载资源 -->
- <param-value>com.jerseyserver.RestApplication</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <!-- 保持和servlet名一致 -->
- <servlet-name>mobile</servlet-name>
- <!-- 分发根路径,用来做路径映射-->
- <url-pattern>/rest/*</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>index.html</welcome-file>
- <welcome-file>index.htm</welcome-file>
- <welcome-file>index.jsp</welcome-file>
- <welcome-file>default.html</welcome-file>
- <welcome-file>default.htm</welcome-file>
- <welcome-file>default.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
web.xml中需要注意的项已经标注在了注释里面,其中有一个资源加载类RestApplication.java用于加载各种资源和所需工具,代码如下:
- package com.jerseyserver;
- import org.glassfish.jersey.filter.LoggingFilter;
- import org.glassfish.jersey.server.ResourceConfig;
- import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
- public class RestApplication extends ResourceConfig {
- public RestApplication() {
- // 服务类所在的包路径
- packages("com.jerseyserver.service");
- // 注册JSON转换器
- register(JacksonJsonProvider.class);
- // 打印访问日志,便于跟踪调试,正式发布可清除
- register(LoggingFilter.class);
- }
- }
这里,主要指定了服务类的包路径,并用Jackson作为Json的解析转换工具,用glassfish的LoggingFilter打印日志。
此外,项目中的User实体类代码如下:
- package com.jerseyserver.entity;
- import javax.xml.bind.annotation.XmlRootElement;
- @XmlRootElement
- public class User {
- private String name;
- private String passwd;
- private String age;
- private String sex;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPasswd() {
- return passwd;
- }
- public void setPasswd(String passwd) {
- this.passwd = passwd;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- }
注意,需要用@XmlRootElement进行注释才能正常传递实体数据。
ResponseDTO.java用于包装返回给客户端的JSON数据,包括返回状态码,返回状态值以及实体数据,代码如下:
- package com.jerseyserver.entity;
- public class ResponseDTO {
- private int status;
- private String message;
- private Object response;
- public ResponseDTO(int status, String message, Object response) {
- super();
- this.status = status;
- this.message = message;
- this.response = response;
- }
- public int getStatus() {
- return status;
- }
- public void setStatus(int status) {
- this.status = status;
- }
- public String getMessage() {
- return message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- public Object getResponse() {
- return response;
- }
- public void setResponse(Object response) {
- this.response = response;
- }
- }
好了,到此服务端就搞定了,接下来让我们简单看看android端的实现。客户端的项目结构如下:
- package com.jy.jerseyclient.service;
- import android.text.TextUtils;
- import android.util.Log;
- import com.jy.jerseyclient.entity.Response;
- import com.jy.jerseyclient.utils.JsonUtil;
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.net.URLEncoder;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * Created by xy on 2016/4/10.
- */
- public class WebService {
- private final static String TAG = "WebService";
- /**服务器接口根路径*/
- private static final String WEB_ROOT = "http://192.168.254.26:8080/JerseyServer/rest/restService/";
- /**登录*/
- private static final String LOGIN = "login";
- /**获取所有用户信息*/
- private static final String GET_ALL_USERS = "getAllUsers";
- /**
- * 登录
- * @param username 用户名
- * @param password 用户密码
- * @return 包含用户信息的Response对象
- */
- public static Response login(String username, String password) {
- String path = WEB_ROOT + LOGIN;
- Map<String, String> map = new HashMap<>();
- map.put("username", username);
- map.put("password", password);
- InputStream is = connection(path, map);
- if (is != null) {
- String content = getStringFromIS(is);
- if (content != null) {
- return parseResponse(content);
- } else {
- Log.e(TAG, "contentS == null");
- }
- } else {
- Log.e(TAG, "is == null");
- }
- return null;
- }
- /**
- * 获取所有用户信息
- * @return 包含所有用户信息的Response对象
- */
- public static Response getAllUsers() {
- String path = WEB_ROOT + GET_ALL_USERS;
- InputStream is = connection(path, null);
- if (is != null) {
- String content = getStringFromIS(is);
- if (content != null) {
- return parseResponse(content);
- } else {
- Log.e(TAG, "contentS == null");
- }
- } else {
- Log.e(TAG, "is == null");
- }
- return null;
- }
- /**
- * 解析服务器返回的JSON数据
- * @param content JSON数据
- * @return Response对象
- */
- private static Response parseResponse(String content) {
- Log.e(TAG, "state======" + content);
- if (TextUtils.isEmpty(content)) {
- return null;
- }
- return JsonUtil.getEntity(content, Response.class);
- }
- /**
- * 得到服务器返回的输入流数据
- * @param path 请求路径
- * @param map 包含密文的map集合
- * @return 服务器返回的数据
- */
- private static InputStream connection(String path, Map<String, String> map) {
- try {
- String pathUrl = path;
- URL url = new URL(pathUrl);
- HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
- StringBuffer sb = new StringBuffer();
- if (map != null) {
- if (!map.isEmpty()) {
- for (Map.Entry<String, String> entry : map.entrySet()) {
- sb.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), "UTF-8")).append('&');
- }
- sb.deleteCharAt(sb.length() - 1);
- }
- }
- byte[] entityData = sb.toString().getBytes();
- httpConn.setDoOutput(true);
- httpConn.setDoInput(true);
- httpConn.setUseCaches(false);
- httpConn.setRequestMethod("POST");
- //设置请求服务器连接的超时时间
- httpConn.setConnectTimeout(5 * 1000);
- //设置服务器返回数据的超时时间
- //httpConn.setReadTimeout(30 * 1000);
- httpConn.setRequestProperty("Content-length", "" + entityData.length);
- httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- OutputStream outStream = httpConn.getOutputStream();
- outStream.write(entityData);
- outStream.flush();
- outStream.close();
- int responseCode = httpConn.getResponseCode();
- if (HttpURLConnection.HTTP_OK == responseCode) {
- InputStream is = httpConn.getInputStream();
- return is;
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- return null;
- }
- /**
- * 将服务器返回的输入流转换为字符串
- * @param is 服务器返回的输入流
- * @return 输入流转换之后的字符串
- */
- public static String getStringFromIS(InputStream is) {
- byte[] buffer = new byte[1024];
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- try {
- int len = -1;
- while ((len = is.read(buffer)) != -1) {
- os.write(buffer, 0, len);
- }
- os.close();
- is.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- String reString = new String(os.toByteArray());
- Log.e(TAG, "geStringFromIS reString======" + reString);
- return reString;
- }
- }
其中,使用HttpURLConnection向服务器发送请求数据,用GSON来解析JSON数据,在解析JSON的时候,为了解析的方便,我对GSON进行了进一步封装,以便在接口中对所有的实体和JSON进行统一的转换,其实现代码如下:
- package com.jy.jerseyclient.utils;
- import android.util.Log;
- import com.google.gson.Gson;
- import com.google.gson.JsonArray;
- import com.google.gson.JsonElement;
- import com.google.gson.JsonParser;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Created by xy on 2015/12/29.
- */
- public class JsonUtil {
- private final static String TAG = "JsonUtil";
- /**
- * 将对象转换为json字符串
- * @param obj 对象,可以是实体对象,List对象,Map对象等
- * @return json字符串
- */
- public static String toJson(Object obj) {
- if (obj == null) {
- throw new IllegalArgumentException("illegal argument");
- }
- return new Gson().toJson(obj);
- }
- /**
- * 将json字符串转换为实体对象
- * @param jsonString json字符串
- * @param cls 实体类
- * @param <T> 泛型参数
- * @return 实体对象
- */
- public static <T> T getEntity(String jsonString, final Class<T> cls) {
- T t;
- try {
- Gson gson = new Gson();
- t = gson.fromJson(jsonString, cls);
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(TAG, jsonString + " 无法转换为 " + cls.getSimpleName() + " 对象");
- return null;
- }
- return t;
- }
- /**
- * 将json字符串转换为List对象
- * @param jsonString json字符串
- * @param cls 实体类
- * @param <T> 泛型参数
- * @return 实体List对象
- */
- public static <T> List<T> getEntityList(String jsonString, final Class<T> cls) {
- List<T> list = new ArrayList<T>();
- JsonArray array = new JsonParser().parse(jsonString).getAsJsonArray();
- for (final JsonElement elem : array) {
- list.add(new Gson().fromJson(elem, cls));
- }
- return list;
- }
- }
同服务端一样,客户端也用一个Response类封装实体对象的信息。
Response.java的代码如下:
- package com.jy.jerseyclient.entity;
- import java.io.Serializable;
- /**
- * Description:
- * Author: xy
- * Date: 2016/4/12 14:49
- */
- public class Response implements Serializable {
- private static final long serialVersionUID = 8980216391057926016L;
- public int status;
- public String message;
- public Object response;
- public int getStatus() {
- return status;
- }
- public void setStatus(int status) {
- this.status = status;
- }
- public String getMessage() {
- return message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- public Object getResponse() {
- return response;
- }
- public void setResponse(Object response) {
- this.response = response;
- }
- }
User.java的代码如下:
- package com.jy.jerseyclient.entity;
- import java.io.Serializable;
- /**
- * Created by 123 on 2016/4/10.
- */
- public class User implements Serializable {
- private static final long serialVersionUID = -1044671445753823751L;
- private String name;
- private String passwd;
- private String sex;
- private String age;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPasswd() {
- return passwd;
- }
- public void setPasswd(String passwd) {
- this.passwd = passwd;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "User{" +
- "name='" + name + '\'' +
- ", passwd='" + passwd + '\'' +
- ", sex='" + sex + '\'' +
- ", age='" + age + '\'' +
- '}';
- }
- }
NetworkUtil.java用于网络状况的判断,实现代码如下:
- package com.jy.jerseyclient.utils;
- import android.content.Context;
- import android.net.ConnectivityManager;
- /**
- * 网络相关工具类
- * @author xy
- *
- */
- public class NetworkUtil {
- /**
- * 判断是否有可用网络
- * @param context
- * @return
- */
- public static boolean isNetWorkOpened(Context context) {
- ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (connManager.getActiveNetworkInfo() != null) {
- return connManager.getActiveNetworkInfo().isAvailable();
- }
- return false;
- }
- }
好了,剩下的就是登陆界面和主界面了,Activity的布局和逻辑都非常简单,我直接把代码贴上。
LoginActivty:
- package com.jy.jerseyclient;
- import android.content.Intent;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.text.TextUtils;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.Toast;
- import com.jy.jerseyclient.entity.Response;
- import com.jy.jerseyclient.entity.User;
- import com.jy.jerseyclient.service.WebService;
- import com.jy.jerseyclient.utils.JsonUtil;
- import com.jy.jerseyclient.utils.NetworkUtil;
- public class LoginActivity extends AppCompatActivity {
- private final static String TAG = "LoginActivity";
- private EditText edt_username;
- private EditText edt_password;
- private Button btn_login;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_login);
- initView();
- initEvent();
- }
- private void initView() {
- edt_username = (EditText) findViewById(R.id.edt_username);
- edt_password = (EditText) findViewById(R.id.edt_password);
- btn_login = (Button) findViewById(R.id.btn_login);
- }
- private void initEvent() {
- btn_login.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- final String username = edt_username.getText().toString();
- if (TextUtils.isEmpty(username)) {
- Toast.makeText(LoginActivity.this,
- "user name must not be empty", Toast.LENGTH_SHORT).show();
- return;
- }
- final String password = edt_password.getText().toString();
- if (TextUtils.isEmpty(password)) {
- Toast.makeText(LoginActivity.this,
- "password must not be empty", Toast.LENGTH_SHORT).show();
- return;
- }
- if (NetworkUtil.isNetWorkOpened(LoginActivity.this)) {
- new AsyncTask<String, Integer, Response>() {
- @Override
- protected Response doInBackground(String... params) {
- Response response = WebService.login(username, password);
- return response;
- }
- @Override
- protected void onPostExecute(Response response) {
- if (response == null) {
- Toast.makeText(LoginActivity.this, "login failed,response is null",
- Toast.LENGTH_SHORT).show();
- } else if (200 == response.getStatus()) {
- Log.e(TAG, "user======" + response.toString());
- Object obj = response.getResponse();
- if (obj == null) {
- Toast.makeText(LoginActivity.this,
- "login failed,the response field is null",
- Toast.LENGTH_SHORT).show();
- } else {
- User user = JsonUtil.getEntity(obj.toString(), User.class);
- if (user == null) {
- Toast.makeText(LoginActivity.this, "login failed,illegal json",
- Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(LoginActivity.this, "login succeed",
- Toast.LENGTH_SHORT).show();
- Intent intent = new Intent(LoginActivity.this, MainActivity.class);
- intent.putExtra("user", user);
- startActivity(intent);
- finish();
- }
- }
- } else {
- Toast.makeText(LoginActivity.this,
- "login failed," + response.getMessage(),
- Toast.LENGTH_SHORT).show();
- }
- super.onPostExecute(response);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- Toast.makeText(LoginActivity.this,
- "network is not available", Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- }
LoginActivty的布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity"
- android:orientation="vertical"
- android:background="#FFFFFF"
- android:gravity="center" >
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
- <TextView
- android:id="@+id/tv_username"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="用户名"
- android:textSize="18sp"
- android:layout_alignParentLeft="true" />
- <EditText
- android:id="@+id/edt_username"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_toRightOf="@id/tv_username"
- android:textSize="18sp" />
- </RelativeLayout>
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp" >
- <TextView
- android:id="@+id/tv_password"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="密 码"
- android:textSize="18sp"
- android:layout_alignParentLeft="true" />
- <EditText
- android:id="@+id/edt_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_toRightOf="@id/tv_password"
- android:inputType="textPassword"
- android:textSize="18sp" />
- </RelativeLayout>
- <Button
- android:id="@+id/btn_login"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="登录"
- android:textSize="18sp"
- android:gravity="center"
- android:layout_marginTop="50dp" />
- </LinearLayout>
MainActivity:
- package com.jy.jerseyclient;
- import android.content.Intent;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.jy.jerseyclient.entity.Response;
- import com.jy.jerseyclient.entity.User;
- import com.jy.jerseyclient.service.WebService;
- import com.jy.jerseyclient.utils.JsonUtil;
- import com.jy.jerseyclient.utils.NetworkUtil;
- import java.util.ArrayList;
- public class MainActivity extends AppCompatActivity {
- private final static String TAG = "MainActivity";
- private TextView tv_welcome;
- private Button btn_show_all_users;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- initEvent();
- initData();
- }
- private void initView() {
- tv_welcome = (TextView) findViewById(R.id.tv_welcome);
- btn_show_all_users = (Button) findViewById(R.id.btn_show_all_users);
- }
- private void initEvent() {
- btn_show_all_users.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (NetworkUtil.isNetWorkOpened(MainActivity.this)) {
- new AsyncTask<String, Integer, Response>() {
- @Override
- protected Response doInBackground(String... params) {
- Response response = WebService.getAllUsers();
- return response;
- }
- @Override
- protected void onPostExecute(Response response) {
- if (response == null) {
- Toast.makeText(MainActivity.this,
- "request failed,response is null",
- Toast.LENGTH_SHORT).show();
- } else if (200 == response.getStatus()) {
- Log.e(TAG, "user======" + response.toString());
- Object obj = response.getResponse();
- if (obj == null) {
- Toast.makeText(MainActivity.this,
- "request failed,the response field is null",
- Toast.LENGTH_SHORT).show();
- } else {
- ArrayList<User> users = (ArrayList<User>)
- JsonUtil.getEntityList(obj.toString(), User.class);
- if (users == null) {
- Toast.makeText(MainActivity.this,
- "request failed,illegal json",
- Toast.LENGTH_SHORT).show();
- } else {
- StringBuilder allUserInfo = new StringBuilder();
- for (User u : users) {
- allUserInfo.append(u.getName() + ":" + u.getSex() + ","
- + u.getAge() + "\n");
- }
- tv_welcome.setText(allUserInfo);
- }
- }
- } else {
- Toast.makeText(MainActivity.this,
- "request failed," + response.getMessage(),
- Toast.LENGTH_SHORT).show();
- }
- super.onPostExecute(response);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- Toast.makeText(MainActivity.this,
- "network is not available", Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- private void initData() {
- Intent intent = getIntent();
- if (intent != null) {
- User user = (User) intent.getExtras().getSerializable("user");
- if (user != null) {
- tv_welcome.setText("Welcome," + user.getName());
- }
- }
- }
- }
MainActivty的布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true"
- tools:context=".MainActivity">
- <TextView
- android:id="@+id/tv_welcome"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="欢迎您"
- android:textSize="18sp" />
- <Button
- android:id="@+id/btn_show_all_users"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="显示所有用户"
- android:textSize="18sp"
- android:layout_below="@id/tv_welcome"
- android:layout_marginTop="20dp" />
- </RelativeLayout>
最后,别忘了配置清单文件,如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.jy.jerseyclient" >
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".LoginActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".MainActivity" />
- </application>
- </manifest>
好了,到此客户端和服务端均已大功告成,整个项目其实就是用最简单的模型来说明怎样利用Jersey这个框架来为我们的移动端搭建后台接口,其中,难免有诸多纰漏之处,请大家多多批评指正,谢谢!
最后,附上项目源码的下载链接:
客户端:①http://download.csdn.net/detail/owoxiangxin12/9492575 ②https://github.com/monkey1992/JerseyClient
服务端:①http://download.csdn.net/detail/owoxiangxin12/9492571 ②https://github.com/monkey1992/JerseyServer
用Jersey为Android客户端开发Restful Web Service的更多相关文章
- 使用Jersey和Jetty开发RESTful Web service
Jersey RESTful 框架是开源的RESTful框架, 实现了JAX-RS (JSR 311 & JSR 339) 规范,是JAX-RS的参考实现,并且提供了更多的特性和工具,简化了R ...
- 使用JAX-RS创建RESTful Web Service
guice resteasy http://www.cnblogs.com/ydxblog/p/7891224.html http://blog.csdn.net/withiter/article/d ...
- 基于jersey和Apache Tomcat构建Restful Web服务(一)
基于jersey和Apache Tomcat构建Restful Web服务(一) 现如今,RESTful架构已然成为了最流行的一种互联网软件架构,它结构清晰.符合标准.易于理解.扩展方便,所以得到越来 ...
- 使用 Jersey 和 Apache Tomcat 构建 RESTful Web 服务
作者: Yi Ming Huang, 软件工程师, IBM Dong Fei Wu, 软件工程师, IBM Qing Guo, 软件工程师, IBM 出处: http://www.ibm.com/de ...
- JAX-RS 方式的 RESTful Web Service 开发
JAX-RS 方式的 RESTful Web Service 开发 ——基于 CXF+Spring 的实现 Web Service 目前在风格上有两大类,一个是基于 SOAP 协议,一个是完全遵循 H ...
- 【转】 Build a RESTful Web service using Jersey and Apache Tomcat 2009
Build a RESTful Web service using Jersey and Apache Tomcat Yi Ming Huang with Dong Fei Wu, Qing GuoP ...
- iOS客户端开发与Web前端开发
转载自:http://blog.cnbang.net/tech/1813/不知不觉做iOS客户端开发已经半年多了,了解到iOS客户端开发与Web前端开发的一些异同,写一下. 版本升级.用户角度上看,客 ...
- 基于jersey和Apache Tomcat构建Restful Web服务(二)
基于jersey和Apache Tomcat构建Restful Web服务(二) 上篇博客介绍了REST以及Jersey并使用其搭建了一个简单的“Hello World”,那么本次呢,再来点有趣的东西 ...
- 【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)
转载:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.html 一,选择一个合适的,Web开发环境: 我选择的是Eclip ...
随机推荐
- 2018ACM山东省赛 Games(dp取数)
Games Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description Alice and Bob ...
- uoj#340. 【清华集训2017】小 Y 和恐怖的奴隶主(矩阵加速)
传送门 uoj上的数据太毒了--也可能是我人傻常数大的缘故-- 三种血量的奴隶主加起来不超过\(8\)个,可以枚举每种血量的奴隶主个数,那么总的状态数只有\(165\)种,设\(dp_{t,i,j,k ...
- Macbook 修复Office Excel 异常问题
manbook 版本的office excel 在一次崩溃后,每次打开excel 文件都会弹出以下烦人的错误告警,并且每次都会重新打开很多过去保存过的excel 文件. “在应用程序意外退出之前,Ex ...
- eclipse 通过svn导入maven工程
http://blog.csdn.net/zdnlp/article/details/7238194
- shell脚本编程入门
Linux的Shell种类众多,这里我们关注的重点是Bash. 基本语法 环境变量$PATH IO重定向: 以<改变标准输入 如:tr -d '\r' < dos-file.txt 以& ...
- thinkphp5使用前置后置操作
下面举个例子,前置删除的例子 模型事件只可以在调用模型的方法才能生效,使用查询构造器通过Db类操作是无效的 控制器中实例化类 $cate=model('cate'); $cate-> ...
- Linux上传下载工具 lrzsz
- Spring @Import 注解
@Import 导入某个bean 文件 @Configuration @Import({User.class,MyImportSelector.class,MyImportBeanDefinitio ...
- Token认证登录以及权限控制
IdentityServer4实现Token认证登录以及权限控制 相关知识点 不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下: 蟋蟀大神的: ...
- NET Core源代码通过Autofac实现依赖注入
查看.NET Core源代码通过Autofac实现依赖注入到Controller属性 阅读目录 一.前言 二.使用Autofac 三.最后 回到目录 一.前言 在之前的文章[ASP.NET Cor ...