[关闭]
@Tyhj 2016-12-06T07:25:24.000000Z 字数 8228 阅读 1400

后台开发初体验

Java

原文 https://www.zybuluo.com/Tyhj/note/585487

自己写Android也已经两年了,平时和其他同学合作都是别人写后台,或者直接用第三方的Api,把数据存到别人服务器上面,自己也了解过后台就是自己从来没有去实现过,所以现在感觉没什么事情,就想要自己搞一下。
之前考虑过用Python,但是还要去学习好久的基本语法,自己也是懒得去学了,还是来用Java好了。

基本数据传输

环境配置

环境配置什么的我就不想说了,很简单
把Android端作为客户端,用eclipse或者Myeclipse写服务器端,需要环境:

反正能写Java,Android和Jsp,再安装个Tomcat就好了,Myeclipse应该自带了Tomcat,但是需要破解,其他三个是开源的。

实现服务器接收和反馈信息

新建一个web project工程

新建一个servlet

在写java的文件夹下面选择新建一个servlet,新建好了以后应该是已经继承了HttpServlet并且重写了doGet和doPost方法

配置servlet

新建了servlet后现在还不能通过url来直接访问,必须先在web.xml里面配置后才可以访问,我的配置如下

  1. <servlet>
  2. <servlet-name>sign_up</servlet-name>
  3. <servlet-class>servlet.Signup</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>sign_up</servlet-name>
  7. <url-pattern>/talk/sign_up</url-pattern>
  8. </servlet-mapping>

在WebContent/WEB-INF下面,如果找不到就是创建工程的时候没有选择生成,需要重新创建工程并选择生成web.xml,每个软件或者版本都可能不一样

就是两个标签,
其中servlet-name必须一样,servlet-class就是这个类的路径,就是包名.类名,
url-pattern就是url有关,可以随便写,比如我的要访问这个servlet,url就是

http://192.168.31.215:8080/Talk/talk/sign_up

其中192.168.31.215是你的ip地址
8080是端口,tomcat端口一般是8080
Talk是项目名

本地测试的,让电脑和手机连接同一个WiFi,然后在终端输入,就看到了ip地址

  1. macifconfig
  2. en0下面:
  3. inet 192.168.31.215 netmask 0xffffff00 broadcast
  1. windowsipconfig
  2. 应该是IPv4:
  3. 无线局域网适配器 WLAN:
  4. IPv4 地址 . . . . . . . . . . . . : 192.168.31.104
  5. 子网掩码 . . . . . . . . . . . . : 255.255.255.0
  6. 默认网关. . . . . . . . . . . . . : 192.168.31.1

接收数据

在doGet和doPost里面接收数据,具体在那个里面自己随便写,会决定客户端请求的方式,可以先看一下Http协议的get和post的区别。

接收格式为:

  1. request.setCharacterEncoding("UTF-8");
  2. response.setCharacterEncoding("UTF-8");
  3. String username = request.getParameter("username");
  4. String password = request.getParameter("password");

其中username和password就是在客户端发来的数据。

Android studio的编码是UTF-8,所以我们设置编码格式避免乱码

返回数据给客户端

返回数据给客户端,好让客户端知道请求成功没有,或者返回所请求的资源。这里一般是要用一种固定格式的,以便于客户端好解析,所以我们这里用json格式来包装数据,当然需要导入jar包,下载,复制到项目lib目录,然后,build to path就好了,我用的是google-gson,下载地址为:

http://repo1.maven.org/maven2/com/google/code/gson/gson/2.3.1/gson-2.3.1.jar

现在随便返回一些值,把数据封装到json中:

  1. JsonObject json = new JsonObject();
  2. json.addProperty("code", "1");
  3. json.addProperty("name", username);
  4. json.addProperty("pas", password);

然后把json转成字符串

  1. String postJson =json.toString();

最后返回给客户端

  1. PrintWriter out = response.getWriter();
  2. out.write(postJson);
  3. out.close();

这样的过程应该是比较合理的,客户端拿到数据后就可以轻松地解析出数据,开头一般设置一个状态码,让用户知道请求是不是成功了。

Android端发送请求并获得返回值

新建一个Android项目

发起请求

新建一个类叫Myhttp,用于保存一些发送http请求的方法

在Android中有几种不同的方法发起http请求,我会用HttpURLConnection方法来请求。post和get请求的方法也是不一样的

Post请求方法,获取返回的数据并转成Json格式
  1. public static JSONObject getJson_Post(String data, String url) {
  2. HttpURLConnection conn = null;
  3. URL mURL = null;
  4. try {
  5. mURL = new URL(url);
  6. conn = (HttpURLConnection) mURL.openConnection();
  7. conn.setRequestMethod("POST");
  8. conn.setReadTimeout(5000);
  9. conn.setConnectTimeout(10000);
  10. conn.setDoOutput(true);
  11. OutputStream out = conn.getOutputStream();
  12. out.write(data.getBytes());
  13. out.flush();
  14. out.close();
  15. int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方
  16. if (responseCode == 200) {
  17. //获取到的返回值
  18. InputStream is = conn.getInputStream();
  19. //将返回值转化成字符串
  20. String state = getStringFromInputStream(is);
  21. Log.e("Tag",state);
  22. //将字符串转化成Json格式
  23. JSONObject jsonObject = new JSONObject(state);
  24. if (jsonObject != null)
  25. return jsonObject;
  26. }
  27. return null;
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. return null;
  31. }
  32. }
Post请求方法,获取返回的数据并转成Json格式
  1. public static JSONObject getJson_Get(String data, String url) {
  2. HttpURLConnection conn = null;
  3. URL mURL = null;
  4. try {
  5. mURL = new URL(url + "?" + data);
  6. conn = (HttpURLConnection) mURL.openConnection();
  7. conn.setRequestMethod("GET");
  8. conn.setReadTimeout(5000);
  9. conn.setConnectTimeout(10000);
  10. InputStream is = conn.getInputStream();
  11. String state = getStringFromInputStream(is);
  12. //Log.e("Tag",state);
  13. JSONObject jsonObject = new JSONObject(state);
  14. if (jsonObject != null)
  15. return jsonObject;
  16. return null;
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. return null;
  20. }
  21. }

这是基本的http请求,我们可以在任何Post和Get请求调用它,我们请求成功后拿到返回值再根据实际功能进行解析,其中获取到的字符串是这个样子的:

  1. {"code":"1","name":"嗨","pas":"你好"}

调用方法和解析数据

首先要开启访问网络权限,然后开启线程,在线程中执行,get就是执行doGet,Post同理。
其中data就是你要传给服务器的参数,url就是地址。

  1. String url="http://192.168.31.215:8080/Talk/talk/sign_up";
  2. new Thread(new Runnable() {
  3. @Override
  4. public void run() {
  5. JSONObject jsonObject=MyHttp.getJson_Post("username=嗨&password=你好",url);
  6. try {
  7. String code=jsonObject.getString("code");
  8. String name=jsonObject.getString("name");
  9. String pas=jsonObject.getString("pas");
  10. } catch (JSONException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. }).start();

这样就完成了基本的数据传输。

文件上传

服务器端

使用Apache开发的文件上传处理库Commons FileUpload来进行文件的上传,这个库还可以,有很多优点,上传的文件可大可小。
需要这俩jar包
commons-fileupload.jar:

下载地址:http://apache.fayea.com//commons/fileupload/binaries/commons-fileupload-1.3.2-bin.zip

commons-io.jar

下载地址:http://mirrors.hust.edu.cn/apache//commons/io/binaries/commons-io-2.5-bin.zip

新建servlet

新建一个servlet,然后在web.xml中配置好

  1. <servlet>
  2. <servlet-name>upload</servlet-name>
  3. <servlet-class>servlet.Upload</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>upload</servlet-name>
  7. <url-pattern>/talk/setHeadImage</url-pattern>
  8. </servlet-mapping>

在doPost中完成文件的读取和保存

  1. System.out.println(name + "doPost+被访问");
  2. request.setCharacterEncoding("UTF-8");
  3. response.setCharacterEncoding("UTF-8");
  4. //获得磁盘文件条目工厂。
  5. DiskFileItemFactory factory = new DiskFileItemFactory();
  6. //获取文件上传需要保存的路径,upload文件夹需存在。
  7. String path ="/Users/Tyhj/softWare/upload";
  8. //设置暂时存放文件的存储室,这个存储室可以和最终存储文件的文件夹不同。因为当文件很大的话会占用过多内存所以设置存储室。
  9. factory.setRepository(new File(path));
  10. //设置缓存的大小,当上传文件的容量超过缓存时,就放到暂时存储室。
  11. factory.setSizeThreshold(1024*1024);
  12. //上传处理工具类(高水平API上传处理?)
  13. ServletFileUpload upload = new ServletFileUpload(factory);
  14. try{
  15. //调用 parseRequest(request)方法 获得上传文件 FileItem 的集合list 可实现多文件上传。
  16. List<FileItem> list = (List<FileItem>)upload.parseRequest(request);
  17. for(FileItem item:list){
  18. //获取表单属性名字。
  19. String name = item.getFieldName();
  20. //如果获取的表单信息是普通的文本信息。即通过页面表单形式传递来的字符串。
  21. if(item.isFormField()){
  22. //获取用户具体输入的字符串,
  23. String value = item.getString();
  24. request.setAttribute(name, value);
  25. }
  26. //如果传入的是非简单字符串,而是图片,音频,视频等二进制文件。
  27. else{
  28. //获取路径名
  29. String value = item.getName();
  30. //取到最后一个反斜杠。
  31. int start = value.lastIndexOf("\\");
  32. //截取上传文件的 字符串名字。+1是去掉反斜杠。
  33. String filename = value.substring(start+1);
  34. request.setAttribute(name, filename);
  35. /*第三方提供的方法直接写到文件中。
  36. * item.write(new File(path,filename));*/
  37. //收到写到接收的文件中。
  38. OutputStream out = new FileOutputStream(new File(path,filename));
  39. InputStream in = item.getInputStream();
  40. int length = 0;
  41. byte[] buf = new byte[1024];
  42. System.out.println("获取文件总量的容量:"+ item.getSize());
  43. while((length = in.read(buf))!=-1){
  44. out.write(buf,0,length);
  45. }
  46. in.close();
  47. out.close();
  48. }
  49. }
  50. }catch(Exception e){
  51. e.printStackTrace();
  52. }
  53. JsonObject json = new JsonObject();
  54. json.addProperty("code", "1");
  55. json.addProperty("name", "上传成功");
  56. String postJson =json.toString();
  57. System.out.println(postJson);
  58. PrintWriter out = response.getWriter();
  59. out.write(postJson);
  60. out.close();

Android端

Android端也是比较简单,新建一个upLoad方法来执行文件上传的操作

  1. //上传文件
  2. public static String upLoad(String url, File file) {
  3. String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
  4. String PREFIX = "--", LINE_END = "\r\n";
  5. String CONTENT_TYPE = "multipart/form-data"; // 内容类型
  6. HttpURLConnection conn = null;
  7. java.net.URL mURL = null;
  8. try {
  9. mURL = new URL(url);
  10. conn = (HttpURLConnection) mURL.openConnection();
  11. conn.setRequestMethod("POST");
  12. conn.setReadTimeout(5000);
  13. conn.setConnectTimeout(10000);
  14. conn.setDoInput(true); // 允许输入流
  15. conn.setDoOutput(true); // 允许输出流
  16. conn.setUseCaches(false); // 不允许使用缓存
  17. conn.setRequestProperty("connection", "keep-alive");
  18. conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary="+ BOUNDARY);
  19. OutputStream out = conn.getOutputStream();
  20. DataOutputStream dos = new DataOutputStream(out);
  21. StringBuffer sb = new StringBuffer();
  22. sb.append(PREFIX);
  23. sb.append(BOUNDARY);
  24. sb.append(LINE_END);
  25. /**
  26. * 这里重点注意: name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
  27. * filename是文件的名字,包含后缀名
  28. */
  29. sb.append("Content-Disposition: form-data; name=\"file\"; filename=\""
  30. + file.getName() + "\"" + LINE_END);
  31. sb.append("Content-Type: application/octet-stream; charset="
  32. + CHARSET + LINE_END);
  33. sb.append(LINE_END);
  34. dos.write(sb.toString().getBytes());
  35. InputStream is = new FileInputStream(file);
  36. byte[] bytes = new byte[1024];
  37. int len = 0;
  38. while ((len = is.read(bytes)) != -1) {
  39. dos.write(bytes, 0, len);
  40. }
  41. is.close();
  42. dos.write(LINE_END.getBytes());
  43. byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
  44. dos.write(end_data);
  45. dos.flush();
  46. int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方
  47. if (responseCode == 200) {
  48. InputStream input = conn.getInputStream();
  49. String state = For2mat.getInstance().inputStream2String(input);
  50. //Log.e("Tag",state);
  51. return state;
  52. }
  53. return null;
  54. } catch (Exception e) {
  55. e.printStackTrace();
  56. return null;
  57. }
  58. }

总结

之前使用过把文件转化成字符串来上传的方法,但是上传的文件大小有限制,还容易出错,所以这个方法还可以,我也是网上找的代码,没有深入学习过,我测试上传了一个MV,是可以用的,当然我的代码有很多需要优化的地方,服务器返回值应该在文件保存之前返回,不然文件太大的话,会造成请求超时。

其实还有种简单的方法是直接把文件上传到第三方平台,用的时候直接取,这样其实也不错。

参考文章:http://blog.csdn.net/crazy__chen/article/details/41958701

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注