概念

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

httpClient使用

第一步:编写配置文件 HttpClient.properties

#最大连接数
http.maxTotal = 1000
#并发数
http.defaultMaxPerRoute = 20
#创建连接的最长时间
http.connectTimeout=5000
#从连接池中获取到连接的最长时间
http.connectionRequestTimeout=500
#数据传输的最长时间
http.socketTimeout=5000
#提交请求前测试连接是否可用
http.staleConnectionCheckEnabled=true

第二步:写httpClient配置类 HttpClientConfig

package com.jt.config;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * 获取httpClient主要参数配置类
 * @author wangcheng
 */
@Configuration
@PropertySource("classpath:/properties/httpClient.properties")
public class HttpClientConfig {

    /**最大链接数*/
    @Value("${http.maxTotal}")
    private Integer maxTotal;
    /**最大并发链接数*/
    @Value("${http.defaultMaxPerRoute}")
    private Integer defaultMaxPerRoute;
    /**链接最大时间*/
    @Value("${http.connectTimeout}")
    private Integer connectionTimeout;
    /**链接获取最长时间*/
    @Value("${http.connectionRequestTimeout}")
    private Integer connectionRequestTimeout;
    /**数据传输最长时间*/
    @Value("${http.socketTimeout}")
    private Integer socketTimeout;
    /**提交时检查连接是否可用*/
    @Value("${http.staleConnectionCheckEnabled}")
    private  Boolean staleConnectionCheckEnabled;

    /**定义链接池*/
    @Bean("httpClientConnectionManager")
    public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager(){
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(maxTotal);
        connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
        return connectionManager;
    }

    /**定义httpClient创建者*/
    @Bean("httpClientBuilder")
    public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager poolingHttpClientConnectionManager){
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
        return httpClientBuilder;
    }

    /**注入httpClientBuilder,获取httpClient*/
    @Bean
    public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){
        return httpClientBuilder.build();
    }

    /**创建requestConfig创建者*/
    @Bean(name = "builder")
    public RequestConfig.Builder getBuilder(){
        RequestConfig.Builder builder = RequestConfig.custom();
        builder.setConnectTimeout(connectionTimeout)
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setSocketTimeout(socketTimeout)
                .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
        return builder;
    }

    /**
     * 注入requestConfigBuilder获取requestConfig对象
     * @param builder
     * @return
     */
    @Bean
    public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
        return builder.build();
    }
}

第三步:写httpClient服务类 HttpClientService

package com.jt.service;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * @author wangcheng
 */
@Service
public class HttpclientService {
    @Autowired
    private CloseableHttpClient httpClient;
    @Autowired
    private RequestConfig requestConfig;

    public String doGet(String url, Map<String,String> params,String charset){
        if(StringUtils.isEmpty(charset)){
            charset = "UTF-8";
        }
        if (params != null){
            url +="?";
            for (Map.Entry<String,String> param : params.entrySet()) {
                String key = param.getKey();
                String value = param.getValue();
                url = url + key + "=" +value +"&";
            }
            url = url.substring(0,url.length()-1);
        }
        HttpGet httpGet = new HttpGet(url);
        //定义超时时间
        httpGet.setConfig(requestConfig);
        String result = null;
        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200){
                result = EntityUtils.toString(response.getEntity(),charset);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
        return result;
    }

    /**
     * 重载方法
     * @param url
     * @return
     */
    public String doGet(String url){
        return doGet(url,null,null);
    }

    /**
     * 重载方法
     * @param url
     * @param params
     * @return
     */
    public String doGet(String url,Map<String,String> params){
        return doGet(url,params,null);
    }
}

第四步:调用httpClient服务,进行访问

package com.jt.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.util.HttpClientService;
import com.jt.util.ObjectMapperUtil;

@Service
public class ItemServiceImpl implements ItemService {

	@Autowired
	private HttpClientService httpClient;
	@Override
	public Item findItemById(Long itemId) {
		String url = "http://www.jd.com/web/item/findItemById/"+itemId;
		String itemJson = httpClient.doGet(url);
		//将json数据转化为对象,对象转json get方法
		//json转对象调用 set方法
		System.out.println(itemJson);
		return ObjectMapperUtil.toObject(itemJson, Item.class);	
	}
	@Override
	public ItemDesc findItemDescById(Long itemId) {
		String url ="http://www.jd.com/web/item/findDescById/"+itemId;
		String itemDescJson = httpClient.doGet(url);
		System.out.println(itemDescJson);
		return ObjectMapperUtil.toObject(itemDescJson, ItemDesc.class);	 
	}

}

Dubbo使用

第一步:在公共模块中定义Dubbo接口

package com.jt.dubbo;

import com.jt.pojo.User;

/**
 * @author wangcheng
 */
public interface DubboUserService {
    /**
     * web页面实现注册服务接口
     * @param user
     * @return
     */
    int saveUser(User user);

    /**
     * web页面输入信息,sso实现登陆接口
     * @param user
     * @return
     */
    String doLogin(User user);
}

第二步:编写服务提供者,提供者基本上是属于业务实现,是上一步接口的具体实现类以及相关业务处理

package com.jt.jtsso.dubbo;

import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.dubbo.DubboUserService;
import com.jt.jtsso.dao.UserDao;
import com.jt.pojo.User;
import com.jt.utils.ObjectMapperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import redis.clients.jedis.ShardedJedis;

import java.util.Date;

/**
 * @author wangcheng
 */
@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private ShardedJedis shardedJedis;

    @Override
    public int saveUser(User user) {
        //对密码进行加密 利用digestUtils工具类进行加密
        String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setEmail(user.getPhone())
                .setPassword(password)
                .setCreated(new Date())
                .setUpdated(user.getCreated());
        int row = userDao.insert(user);
        return row;
    }

    /**
     * 1.先查询数据库,看用户是否存在
     * 2.将用户信息保存到redis中
     * 3.返回页面token
     * @param user
     * @return
     */
    @Override
    public String doLogin(User user) {
        String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>(user);
        User userDB = userDao.selectOne(queryWrapper);
        String token = null;
        //用户存在
        if (userDB != null){
            String tokenTemp = "JT_TICKET" + System.currentTimeMillis() + userDB.getUsername();
            //将tokenTemp转化十六进制数据,脱敏
            tokenTemp = DigestUtils.md5DigestAsHex(tokenTemp.getBytes());
            userDB.setPassword("123456,你猜对了嘛?");
            String userDBJson = ObjectMapperUtils.toJSON(userDB);
            shardedJedis.setex(tokenTemp,7*24*3600,userDBJson);
            token = tokenTemp;
        }
        return token;
    }
}

服务提供者相关的配置

server:
  port: 8093

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/jdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

#mybatis-plus
mybatis-plus:
  type-aliases-package: com.jd.pojo
  mapper-locations: classpath:/mppers/*.xml
  configuration:
    map-underscore-to-camel-case: true

#配置日志信息
logging:
  level:
    com.jt: debug

#dubbo配置信息
dubbo:
  scan:
    base-packages: com.jd
  application:
    name: provider-user
  registry:
    address: zookeeper://49.235.87.70:2181?backup=49.235.87.70:2182,49.235.87.70:2183
    protocol:
      name: dubbo
      port: 20880

第三步:编写服务消费者,服务消费者是调用接口的服务,通过调用接口进行业务实现。

服务消费者配置:

server:
  port: 8092    
spring:     #定义springmvc视图解析器
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
  resources:
    static-locations: classpath:/META-INF/resources/

#dubbo相关配置
dubbo:
  scan:
    base-packages: com.xx
  application:
    name: consumer-user
  registry:
    address: zookeeper://49.235.87.70:2181?backup=49.235.87.70:2182,49.235.87.70:2183

调用接口:

package com.xx.controller;



/**
 * @author wangcheng
 */
@Controller
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Reference(timeout = 3000,check = false)
    private DubboUserService dubboUserService;
    /**
     * restful风格进行页面跳转
     * @param moduleName
     * @return
     */
    @RequestMapping("/{moduleName}")
    public String pageController(@PathVariable String moduleName){
        return moduleName;
    }

    /**
     * 用户注册,通过dubbo调用sso向数据库插入数据
     * @param user
     * @return
     */
    @RequestMapping("/doRegister")
    @ResponseBody
    public SysResult doUserRegister(User user){
        //dubbo远程调用jt-sso服务实现用户注册
        dubboUserService.saveUser(user);
        return SysResult.success();
    }

    @RequestMapping("/doLogin")
    @ResponseBody
    public SysResult doUserLogin(User user, HttpServletResponse response){
        //用户第一次登陆
        String token = dubboUserService.doLogin(user);

        if (StringUtils.isEmpty(token)){
            log.info("用户不存在,登陆失败");
            return SysResult.fail();
        }
        //用户存在将token封装到cookie,实现用户一定时间内免登录
        Cookie cookie = new Cookie("JT_TICKET",token);
        //设置cookie存活时间
        cookie.setMaxAge(7*24*3600);
        cookie.setPath("/");
        //cookie共享
        cookie.setDomain("xx.com");
        response.addCookie(cookie);
        return SysResult.success();
    }
}

总结:dubbo适合在项目内部使用,实现不同模块服务之间的互相调用,而httpClient适合不同项目之间的远程服务调用