因为最近学习spring cloud组件问题,所以需要使用feign的接口调用方式,而Feign的http调用和RPC调用以及原生Ribbon的RestTemplate请求问题不再称述。
首先加入feign依赖
<!-- feign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
服务提供者(生产者)
//GET请求
//查询全部用户
// @PreAuthorize("hasAnyRole('employee')")
@RequestMapping("/api/findAll")
@ResponseBody
public Object findAllUser(HttpServletResponse response) {
//设置响应头方法,解决ajax跨域问题
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
List<User> userList = userService.findAllUser();
Map<String, Object> jsonMap = new HashMap<String, Object>();
if (userList != null) {
//如果查询数据为空
if (userList.size() == 0) {
return Result.failure(ResultCode.RESULT_EMPTY, userList);//直接用静态方法返回
}
//如果查询数据不为空
return Result.success(ResultCode.SUCCESS, userList);
}else {
return Result.failure(ResultCode.FAIL);
}
}
//Post请求
//新增用户
@PostMapping("/api/insUser")
@ResponseBody
public Object insUser(@RequestBody User user) {//其中@RequstBody注解必不可少
User alreadyUser = userService.selUserByUsername(user.getUserName());
//如果用户已经存在
if (alreadyUser != null) {
return Result.failure(ResultCode.USER_HAS_EXISTED);
}
//记录状态
int data = -1;
if ((data = userService.insUser(user)) > 0) {
return Result.success(ResultCode.SUCCESS, data);
}else
return Result.failure(ResultCode.FAIL, data);
}
@RequestBody:请求以对象的形式传输
@RequestParam:请求以基本数据类型传输
@PathVariable:以Rest请求方式传输基本数据类型
如:
@GetMapping("/api/delete/{id}")
@ResponseBody
public Object delUserById(@PathVariable("id") Integer id) {
/**/
}
Feign客户端
@Service
@FeignClient(value = "resource-server", configuration = {FeignConfiguration.class})//添加配置类名
public interface UserClientService {
@RequestMapping("/api/findAll")
@ResponseBody
public Object findAllUser();
@GetMapping("/api/delete/{id}")
@ResponseBody
Object delUserById(@PathVariable("id") Integer id);
@PostMapping(value = "/api/insUser")
@ResponseBody
Object insUser(@RequestBody User user);
@PostMapping(value = "/api/updUser")
@ResponseBody
Object updUserById(@RequestBody User user);
}
因为需要在请求头中附加token信息,而feign又是以接口方式调用,而不是直接用地址发送请求,所以需要一个feign的配置类,将请求需要携带的token加入到请求头中。
@Configuration
public class FeignConfiguration {
private static String token = "";
@Bean
public RequestInterceptor requestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
//获取请求信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert attributes != null;
HttpServletRequest request = attributes.getRequest();
//获取在session中的token信息
token = (String) request.getSession().getAttribute("token");
System.out.println("RequestTemplateToken-->" + token);
//输出请求中已经存在的请求信息
Map<String,Object> map = new HashMap<String,Object>();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length >0) {
String paramValue = paramValues[0];
if (paramValue.length() != 0) {
map.put(paramName, paramValue);
}
}
}
//迭代
// 输出 key 和 value
for (String i : map.keySet()) {
System.out.println("key: " + i + " value: " + map.get(i));
}
// 返回所有 value 值
for(Object value: map.values()) {
// 输出每一个value
System.out.print(value + ", ");
}
System.out.println();
//在请求头中添加token信息
List<String> accessToken = Lists.newArrayList("Bearer " + token);
// List<String> contentTypeList = Lists.newArrayList("application/x-www-form-urlencoded");
List<String> contentTypeList = Lists.newArrayList("application/json");
// System.out.println("accessToken-->" + accessToken);
Map<String, Collection<String>> headers = ImmutableMap.of("Authorization", accessToken,"Content-Type", contentTypeList);
// Map<String, Collection<String>> headers = ImmutableMap.of("Authorization", accessToken);
// Map<String, Collection<String>> headers = ImmutableMap.of("Content-Type", contentTypeList);
requestTemplate.headers(headers);
}
};
}
}
feign集成了Ribbon负载均衡:
@Configuration
public class MyConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
客户端(消费者)
@GetMapping(value = "/findAll")
@ResponseBody
public Object findAllUsers(HttpServletRequest request, HttpServletResponse response) {
Object result = userClientService.findAllUser();
if (result.equals("")) {
return Result.failure(ResultCode.FAIL);
}
return Result.success(ResultCode.SUCCESS, result);
}
@PostMapping("/updUser")
@ResponseBody
// @Headers("Content-Type=application/json")
public Object updUser(User user, HttpServletRequest request, Authentication authentication) {
UserInfo userInfo = (UserInfo) authentication.getPrincipal();
if (userInfo.getUsername() == null) {
//没有获取到当前用户信息
return Result.failure(ResultCode.USER_INFO_ERROR);
}
user.setUserId(Integer.parseInt(request.getParameter("userId")));
user.setUserName(request.getParameter("userName"));
user.setUserPwd(request.getParameter("userPwd"));
user.setUserRole(request.getParameter("userRole"));
Object result = userClientService.updUserById(user);
return Result.success(ResultCode.SUCCESS, result);
}
- 这里三个微服务最好是请求类型都写一样,要么都是PostMapping,要么都是RequestMapping等
- 我在客户端的User对象传递时没有使用@RequestBody是因为我在前端是以form表单形式传递,即application/x-www-form-urlencoded格式传输,如果加了RequestBody注解的话会报415传递类型不支持错误,所以干脆不加注解。而在feigin调用中是不能以form表单形式传递,只能以json格式传递,所以要加@RequestBody注解转为json格式。
如果请求体较大,会出现超时错误,需要添加配置:
# 配置 feign 默认请求时间仅几秒钟,配置请求时间长一些(毫秒)
feign:
client:
config:
default:
connectTimeout: 10000
readTimeout: 600000
结果
GET查询:
POST查询: