Android(或者Java)通过HttpUrlConnection向SpringMVC请求数据(数据绑定)

问题描述

当我们使用SpringMVC作为服务端的框架时,有时不仅仅要应对web前端(jsp、javascript、Jquery等)的访问请求,有时还可能需要响应Android和JavaSE(桌面应用)这些客户端的请求,因此,除了web使用form表单或者ajax作为客户端获取Controller响应之外,纯Java语言向SpringMVC的Controller提供参数和请求结果也是必须要实现的。web前端使用form和ajax来获取Controller响应在本篇博客暂不深究,本篇博课着力于实现纯Java客户端来实现请求Controller并获取响应。(如果不想看下面的方法探索,可以直接跳到第三部分)

方法探索

确定了需要解决的问题之后,我开始搜索相关的博客和问答,发现这种问题相关解决方法不是很多,找了很多博客都是牛头不对马嘴,但是还是有一些对解决问题有帮助的内容,之后又翻了很久的书,对这个问题的解决方法有了基本的认识。

看网上说的行之有效的方法是使用HttpClient来实现这个功能,不过需要导入HttpClient和HttpCore两个jar包,当时研究了一下觉得可行。但是在实际操作过程中,在向Android(IDE:Android Studio)build.gradle里面导入上述两个jar包的依赖后,同步的时候Android Studio给出了两个警告,大意是HttpClient已经过期云云,然后我又专门去查了一个HttpClient这个东西和Android之间的关系,发现Android6.0以及之后的版本放弃了对HttpClient的支持,强行导入jar包也不行。(据说有人用了非常麻烦的方法导入成功过 = =)那好嘞,不让用算了,那就不用呗。看参考书《疯狂Android讲义》对HttpClient还那么推崇,也是有点醉。具体不让用的原因就不再深究了,接下来就研究使用HttpUrlConnection来解决上述问题吧。

在使用HttpURLConnection的过程中代码实现照着套路来问题不大,遇到的问题是SpringMVC的Controller怎么接收数据,接收的数据格式是什么?我应该传什么类型的数据?

Controller怎么接收数据这个问题经过前段时间的学习我已经有个大概的认识,SpringMVC的Controller工作原理就是客户端向 项目地址+Controller前面的value值 这个url发出请求,这个请求会带有一些参数,而SpringMVC会将请求携带的参数转换为Controller对应value下面的方法的参数,然后在这个方法进行相关的操作再返回客户端一些参数,至于返回的结果就有几种可能了。如果上面没有@ResponseBody注释,返回的数据有可能是jsp页面的名字,则web会跳转到对应的jsp页面如果是ModelAndView也会跳转到对应的页面而如果加上@ResponseBody,那么返回的就是json类型的数据了,客户端会接收到Controller返回的参数。那么,明白了springmvc的工作原理,那么怎么使用HttpUrlConnection来访问Controller就大概清楚了:我们就把请求地址拼接好,然后把携带的数据发送过去就可以等着拿到Controller返回的数据了。那么第二个问题就来了,请求的地址清楚了,携带的数据应该是什么格式的呢?

刚开始我以为和返回值一样是Json格式的键值对形式,比如说用户登录的userName和userPassword,(Controller的参数形式为 doLogin(String userName,String userPassword))开始我以为应该发送json格式数据,可是服务端不鸟我,没有获得参数。后来我又试了jsonArray形式也不行,试了map的键值对形式不行。我就疑惑了到底是什么形式的。最后找了半天看了ajax发出同样请求时的http报文结构才知道了数据格式是什么样子的。是这样的:

中间是一个&连接了两个参数,键值中间是=,好吧,终于明白了。当然这是Controller参数为两个单独的String值的时候的类型,有一种更好的办法是直接把Controller的参数设置为一个,然后在Controller里面解析Json数据,这样其实更方便一点,以后还更容易做加密工作,不过目前改起来太麻烦就不改了吧,现在弄明白了controller是两个参数的时候是这种结构的。至于其它的list,bean以及json类型这里就不探究了,因为我看到很多别的博主都讲了怎么转了。废话了这么多,下面放代码。

解决问题

SpringMVC对应Controller代码(result单词拼错了,懒得改咯):

@RequestMapping(value="/doLogin",method=RequestMethod.POST)
    @ResponseBody
    public Map<String,Object> doLogin(String userName,String userPassword,HttpSession httpSession){
        String resoult="fail";
        User user = userService.getUser(userName);
        UserDetail userDetail = userDetailService.getUserDetail(userName);
        if(user!=null){
            if(Objects.equals(userDetail.getUserDetailPassword(), userPassword)){
                httpSession.setAttribute("currentUser",user);
                resoult = "success";
            }
            else{
                resoult = "wrong";
            }
        }
        else{
            resoult = "unexist";
        }
        Map<String, Object> resoults = new HashMap<String,Object>();
        resoults.put("resoult", resoult);
        return resoults;
    }

Android端或者java端写的一个HttpPostUtils工具类

package cn.justwithme.withme.Utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by 桐木木 on 2017/2/8.
 * 发送Http请求,获取Controller返回的数据
 *
 */

public class HttpPostUtils {
    public static String doPostRequest(String path,Object content){
        PrintWriter out = null;
        BufferedReader in = null;
        String resoult = "";
        try {
            System.out.println("要发送的信息是:"+content);
            /*拼接url,Android这里需要换上远程地址,因为Android端没办法访问localhost,java的话本地tomcat运行的话倒是无妨*/
            String address = http://localhost:8080/WithMe/"+path;
            URL url = new URL(address);
            HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
            //这两个参数必须加
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);
            //设置超时时间
            httpURLConnection.setReadTimeout(10*1000);
            httpURLConnection.setConnectTimeout(10*1000);
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.connect();

            out = new PrintWriter(httpURLConnection.getOutputStream());
            //在输出流中写入参数
            out.print(content);
            out.flush();

            if(httpURLConnection.getResponseCode() == 200){
                in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf-8"));
                String line;
                while((line=in.readLine())!=null){
                    resoult+=line;
                }
            }
            System.out.println("服务器返回的结果是:"+resoult);
            return resoult;
        } catch (MalformedURLException e) {
            System.out.println("URL异常");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("IO异常");
            e.printStackTrace();
        }finally {
            try{
                if(out!=null)
                    out.close();
                if(in!=null)
                    in.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}

工具类写好之后我们分别在Android端和Java端进行一些测试,(在我的服务端我已经注册过14121047的前提下,你如果只是测试把服务端查询数据库校验密码改成字符串匹配就成了)。

Android

LoginActivity.java

package cn.justwithme.withme.Activity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.HashMap;
import java.util.Map;

import cn.justwithme.withme.R;
import cn.justwithme.withme.Utils.HttpPostUtils;

public class LoginActivity extends AppCompatActivity {
    private String result;

    private Handler mHanlder = new Handler() {
        @Override
        public void handleMessage(Message message) {
            result = (String) message.obj;
            JSONObject resultJson = JSON.parseObject(result);
            String finalResult = resultJson.getString("resoult");
            System.out.println("结果是:"+finalResult);
            if(finalResult.equals("success")){
                System.out.println("登陆成功");
            }
            else
                System.out.println("用户名或密码错误");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        final EditText userNameInput = (EditText)findViewById(R.id.userName);
        final EditText passwordInput = (EditText)findViewById(R.id.password);
        Button login = (Button)findViewById(R.id.login);

        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String userName = userNameInput.getText().toString();
                String userPassword = passwordInput.getText().toString();
                final Map<String,Object> userInfo = new HashMap<String,Object>();
                userInfo.put("userName",userName);
                userInfo.put("userPassword",userPassword);
//                UserLogin userInfo = new UserLogin();
//                userInfo.setUserName(userName);
//                userInfo.setUserPassword(userPassword);
                final String user = "userName="+userName+"&userPassword="+userPassword;
                if(userName!= null && !userName.equals("") && userPassword!=null && !userPassword.equals("")){
                    /*这里需要留意的是httpPostUtils请求在Android里面不能放在主线程里面,必须新建一个子线程,然后通过Hanlder把子线程的值传过来更新UI(因为子线程不能直接更改UI)*/
                    new Thread() {
                        public void run() {
                            String response = HttpPostUtils.doPostRequest("doLogin",user);
                            Message message = Message.obtain();
                            message.obj = response;
                            mHanlder.sendMessage(message);
                        }
                    }.start();
                }
                else{
                    System.out.println("用户名密码不能为空");
                }

            }
        });

    }

}

好吧,这是非常简陋的代码,毕竟Android客户端才刚刚开始写,activity_login.xml就不放了,两个输入框一个按钮而已,可以再下面查看输出结果来判断功能是否实现:

下面是Java的测试代码,用的工具类和Android用的一样的,

package httpPost;

public class test {
    public static void main(String[] args){
    String test = "userName=14121047&userPassword=14121047";
    String ans = HttpPostUtils.doPostRequest("doLogin", test);
    System.out.println("服务器返回的数据为:"+ans);
    }
}

测试结果为:

要发送的信息是:userName=14121047&userPassword=14121047
服务器返回的结果是:{"resoult":"success"}
服务器返回的数据为:{"resoult":"success"}

结束语

当然,我这里演示的知识一个非常简单的android和java向springmvc发送请求的例子,但是,既然中间的道理和方法明白了,那之后无论是什么格式的数据都不是很难了。Json数据的那只用一个参数就好了咯,两个参数都传了一个参数不是很容易么?要传bean的先把Bean转json到服务端再把json转bean就好了咯。233。。。(这里只是讨论一下两个参数怎么传,并不是不想用json。)

好好学习,天天向上,加油!

时间: 2024-12-12 09:52:46

Android(或者Java)通过HttpUrlConnection向SpringMVC请求数据(数据绑定)的相关文章

Android或者Java发送Http自动重发请求的解决方案

今天遇到奇葩问题,描述如下: 客户端向服务端发起了一次(从日志中可以看出仅仅打印了一次日志),但是确在后端出现了重复的几次请求数据在后端.这个问题很不容易出现,而且用中文搜索不到相应的结果: 今天在国外的网站中找到了问题的解决方案: 原因如下:由于设置了链接与获取数据的超时时间,客户端在发送数据之后,检测到可能并没有发送成功到后端,这个时候http底层会自动重发请求(注意是Http底层,所以应用端不会知道发送了多次请求).如果应用端自动重发了多次请求,后端也回复了多次请求,但是前段仅仅会只回复1

Java利用HttpURLConnection发送post请求

URL url = null; HttpURLConnection http = null; try { url = new URL(urls); http = (HttpURLConnection) url.openConnection(); http.setDoInput(true); http.setDoOutput(true); http.setUseCaches(false); http.setConnectTimeout(50000);//设置连接超时 //如果在建立连接之前超时期满

Android(java)学习笔记210:采用post请求提交数据到服务器

1.POST请求:  数据是以流的方式写给服务器 优点:(1)比较安全 (2)长度不限制 缺点:编写代码比较麻烦   2.我们首先在电脑模拟下POST请求访问服务器的场景: 我们修改之前编写的login.jsp代码,如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <%@ page language="java"

【黑马Android】(05)短信/查询和添加/内容观察者使用/子线程网络图片查看器和Handler消息处理器/html查看器/使用HttpURLConnection采用Post方式请求数据/开源项目

备份短信和添加短信 操作系统短信的uri: content://sms/ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.itheima28.backupsms" android:versionCode="1

Java服务器对外提供接口以及Android端向服务器请求数据

讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么请求服务器,接收以及解析返回数据的. 服务端:还是在原先S2SH框架的项目上(搭建SSH详细步骤及其相关说明),加入Servlet来做对终端提供接口的事情. Android端:用了一个网络访问框架okHttp,向服务器请求数据. 服务端: servlet接收移动端的get.post请求,进行相应逻辑处理后将要返回的数据封装成json格式写出去. 对数据库的操作传统的Servlet是用jdbc,但是操作过于繁琐,

android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据

主要是基于HTTP协议与服务端进行交互. 涉及到的类和接口有:URL.HttpURLConnection.HttpClient等 URL: 使用一个String类型的url构造一个URL对象,如: URL url = new URL(http://10.0.2.2/index.php); openConnection()方法返回一个对指定url的资源的连接.返回类型是URLConnection,但是,由于这里我们一般用的是http协议,所以返回的实际是HttpURLConnection对象,故一

【JAVA】通过URLConnection/HttpURLConnection发送HTTP请求的方法

Java原生的API可用于发送HTTP请求 即java.net.URL.java.net.URLConnection,JDK自带的类: 1.通过统一资源定位器(java.net.URL)获取连接器(java.net.URLConnection) 2.设置请求的参数 3.发送请求 4.以输入流的形式获取返回内容 5.关闭输入流 封装请求类 1 package com.util; 2 3 import java.io.BufferedReader; 4 import java.io.IOExcept

java 使用原生HttpURLConnection发送post请求

import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Cale

Java学习路线分享SpringMVC之请求和响应

Java学习路线分享SpringMVC之请求和响应,前面我们学习了SpringMVC的基本配置,接下来一个非常重要的知识点是如何接受用户的请求以及如何将数据发送给用户. 获得请求参数 获得页面参数的几种方式 1)通过参数名获得 给控制器的方法设置参数名和表单name相同 2)通过@RequestParam("参数名")注解设置参数 @RequestParam("表单元素的name") 参数类型 参数名 3)自动装箱,创建属性名和表单名称一样的类 把类作为方法的参数