springcloud篇】一. 使用springcloud实现主页后端开发 下

使用springcloud实现主页后端开发

中国加油!武汉加油!

项目准备
  1. 本案例基于使用springcloud实现主页后端开发 中

7. 搭建用户微服务

7.1 在homepage-service这个模块下 创建新的module

7.2 pom引入依赖

<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<dependencies>
    <!-- 引入 Web 功能 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--
        Eureka 客户端, 客户端向 Eureka Server 注册的时候会提供一系列的元数据信息, 例如: 主机, 端口, 健康检查url等
        Eureka Server 接受每个客户端发送的心跳信息, 如果在某个配置的超时时间内未接收到心跳信息, 实例会被从注册列表中移除
    -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- 引入 Feign, 可以以声明的方式调用微服务 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!-- 引入服务容错 Hystrix 的依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <!-- Java Persistence API, ORM 规范 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- MySQL 驱动, 注意, 这个需要与 MySQL 版本对应 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.48</version>
        <scope>runtime</scope>
    </dependency>
    <!-- 通用模块 -->
    <dependency>
        <groupId>com.wpj.homepage</groupId>
        <artifactId>homepage-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

<!--
    SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
    SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

7.3 创建应用程序启动入口

package com.wpj.homepage;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableEurekaClient
@EnableJpaAuditing
@EnableCircuitBreaker
@EnableFeignClients
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

}

7.4 定义application.yml

server:
  port: 7000
  servlet:
    context-path: /homepage-user

spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: eureka-client-homepage-user
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    properties:
      hibernate.format_sql: true
    open-in-view: false
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/springcloud-immoc?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    tomcat:
      max-active: 4
      min-idle: 2
      initial-size: 2

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka/

feign:
  hystrix:
    enabled: true

7.5 定义User实体类和User_Course实体类

package com.wpj.homepage.entity;


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "homepage_user")
public class HomepageUser {
    /** 数据表主键 */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    /** 用户名 */
    @Basic
    @Column(name = "username", nullable = false)
    private String username;

    /** 用户邮箱 */
    @Basic
    @Column(name = "email", nullable = false)
    private String email;

    /** 创建时间 */
    @Basic
    @CreatedDate
    @Column(name = "create_time", nullable = false)
    private Date createTime;

    /** 更新时间 */
    @Basic
    @LastModifiedDate
    @Column(name = "update_time", nullable = false)
    private Date updateTime;

    public HomepageUser(String username, String email) {
        this.username = username;
        this.email = email;
    }
}
package com.wpj.homepage.entity;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;


@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "homepage_user_course")
public class HomepageUserCourse {

    /** 数据表主键 */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    /** 用户 id */
    @Basic
    @Column(name = "user_id", nullable = false)
    private Long userId;

    /** 课程 id */
    @Basic
    @Column(name = "course_id", nullable = false)
    private Long courseId;

    /** 创建时间 */
    @Basic
    @CreatedDate
    @Column(name = "create_time", nullable = false)
    private Date createTime;

    /** 更新时间 */
    @Basic
    @LastModifiedDate
    @Column(name = "update_time", nullable = false)
    private Date updateTime;
}

7.6 定义数据表访问接口

package com.wpj.homepage.dao;

import com.wpj.homepage.entity.HomepageUser;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * 数据表访问接口定义
 */
public interface HomepageUserDao extends JpaRepository<HomepageUser, Long> {

    /**
     * 通过用户名寻找数据记录
     * @param username
     * @return
     */
    HomepageUser findByUsername(String username);
}
package com.wpj.homepage.dao;

import com.wpj.homepage.entity.HomepageUserCourse;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * 数据表访问接口定义
 */
public interface HomepageUserCourseDao extends JpaRepository<HomepageUserCourse, Long> {

    /**
     * 通过用户 id 寻找数据记录
     * */
    List<HomepageUserCourse> findAllByUserId(Long userId);
}

7.7 定义Feign接口及值对象

package com.wpj.homepage.client;

import com.wpj.homepage.CourseInfo;
import com.wpj.homepage.CourseInfosRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

/**
 * 通过 Feign 访问课程微服务
 */
@FeignClient(value = "eureka-client-homepage-course", fallback = CourseClientHystrix.class)
public interface CourseClient {

    @RequestMapping(value = "/homepage-course/get/course", method = RequestMethod.GET)
    CourseInfo getCourseInfo(Long id);

    @RequestMapping(value = "/homepage-course/get/courses", method = RequestMethod.POST)
    List<CourseInfo> getCourseInfos(@RequestBody CourseInfosRequest request);
}
package com.wpj.homepage.client;

import com.wpj.homepage.CourseInfo;
import com.wpj.homepage.CourseInfosRequest;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;

/**
 * 熔断降级
 */
@Component
public class CourseClientHystrix implements CourseClient {

    @Override
    public CourseInfo getCourseInfo(Long id) {
        return CourseInfo.invalid();
    }

    @Override
    public List<CourseInfo> getCourseInfos(CourseInfosRequest request) {
        return Collections.emptyList();
    }
}

7.8 扩展

package com.wpj.homepage.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;

/**
 * 创建用户请求对象定义
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateUserRequest {

    /** 用户名 */
    private String username;

    /** 邮箱 */
    private String email;

    /**
     * 请求有效性验证
     * */
    public boolean validate() {
        return StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(email);
    }
}
package com.wpj.homepage.vo;

import com.wpj.homepage.CourseInfo;
import com.wpj.homepage.UserInfo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.List;

/**
 * 用户课程信息对象定义
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserCourseInfo {

    private UserInfo userInfo;
    private List<CourseInfo> courseInfos;

    public static UserCourseInfo invalid() {
        return new UserCourseInfo(UserInfo.invalid(), Collections.emptyList()
        );
    }
}

7.9 定义User相关服务接口及其实现

package com.wpj.homepage.service;
import com.wpj.homepage.UserInfo;
import com.wpj.homepage.vo.CreateUserRequest;
import com.wpj.homepage.vo.UserCourseInfo;

/**
 * 用户相关服务接口定义
 */
public interface IUserService {

    /**
     * 创建用户
     * */
    UserInfo createUser(CreateUserRequest request);

    /**
     * 获取用户的基本信息
     * */
    UserInfo getUserInfo(Long id);

    /**
     * 获取用户课程信息
     * */
    UserCourseInfo getUserCourseInfo(Long id);
}
package com.wpj.homepage.service.impl;

import com.wpj.homepage.CourseInfo;
import com.wpj.homepage.CourseInfosRequest;
import com.wpj.homepage.UserInfo;
import com.wpj.homepage.client.CourseClient;
import com.wpj.homepage.dao.HomepageUserCourseDao;
import com.wpj.homepage.dao.HomepageUserDao;
import com.wpj.homepage.entity.HomepageUser;
import com.wpj.homepage.entity.HomepageUserCourse;
import com.wpj.homepage.service.IUserService;
import com.wpj.homepage.vo.CreateUserRequest;
import com.wpj.homepage.vo.UserCourseInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用户相关服务实现
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    /** HomepageUser Dao */
    private final HomepageUserDao homepageUserDao;

    /** HomepageUserCourse Dao */
    private final HomepageUserCourseDao homepageUserCourseDao;

    private final CourseClient courseClient;

    @Autowired
    public UserServiceImpl(HomepageUserDao homepageUserDao, HomepageUserCourseDao homepageUserCourseDao,
                           CourseClient courseClient) {
        this.homepageUserDao = homepageUserDao;
        this.homepageUserCourseDao = homepageUserCourseDao;
        this.courseClient = courseClient;
    }

    @Override
    public UserInfo createUser(CreateUserRequest request) {

        if (!request.validate()) {
            return UserInfo.invalid();
        }

        HomepageUser oldUser = homepageUserDao.findByUsername(request.getUsername());
        if (null != oldUser) {
            return UserInfo.invalid();
        }

        HomepageUser newUser = homepageUserDao.save(new HomepageUser(
                request.getUsername(), request.getEmail()
        ));

        return new UserInfo(newUser.getId(), newUser.getUsername(), newUser.getEmail());
    }

    @Override
    public UserInfo getUserInfo(Long id) {

        Optional<HomepageUser> user = homepageUserDao.findById(id);
        if (!user.isPresent()) {
            return UserInfo.invalid();
        }

        HomepageUser curUser = user.get();
        return new UserInfo(curUser.getId(), curUser.getUsername(), curUser.getEmail());
    }

    @Override
    public UserCourseInfo getUserCourseInfo(Long id) {

        Optional<HomepageUser> user = homepageUserDao.findById(id);
        if (!user.isPresent()) {
            return UserCourseInfo.invalid();
        }

        HomepageUser homepageUser = user.get();
        UserInfo userInfo = new UserInfo(homepageUser.getId(), homepageUser.getUsername(),
                homepageUser.getEmail());

        List<HomepageUserCourse> userCourses = homepageUserCourseDao.findAllByUserId(id);
        if (CollectionUtils.isEmpty(userCourses)) {
            return new UserCourseInfo(userInfo, Collections.emptyList());
        }

        List<CourseInfo> courseInfos = courseClient.getCourseInfos(
                new CourseInfosRequest(
                        userCourses.stream().map(HomepageUserCourse::getCourseId).collect(Collectors.toList())
                )
        );

        return new UserCourseInfo(userInfo, courseInfos);
    }
}

7.10 定义Controller

package com.wpj.homepage.controller;

import com.alibaba.fastjson.JSON;
import com.wpj.homepage.UserInfo;
import com.wpj.homepage.service.IUserService;
import com.wpj.homepage.vo.CreateUserRequest;
import com.wpj.homepage.vo.UserCourseInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * 用户对外服务接口
 */
@Slf4j
@RestController
public class HomepageUserController {

    /** 用户服务 */
    private final IUserService userService;

    @Autowired
    public HomepageUserController(IUserService userService) {
        this.userService = userService;
    }

    /**
     * 创建用户
     */
    @PostMapping("/create/user")
    public UserInfo createUser(@RequestBody CreateUserRequest request) {

        log.info("<homepage-user>: create user -> {}", JSON.toJSONString(request));
        return userService.createUser(request);
    }

    /**
     * 获取用户信息
     */
    @GetMapping("/get/user")
    public UserInfo getUserInfo(Long id) {

        log.info("<homepage-user>: get user -> {}", id);
        return userService.getUserInfo(id);
    }

    /**
     * 获取用户课程信息
     */
    @GetMapping("/get/user/course")
    public UserCourseInfo getUserCourseInfo(Long id) {
        log.info("<homepage-user>: get user course info -> {}", id);
        return userService.getUserCourseInfo(id);
    }
}

7.11 接口功能测试

  1. 在Test下创建resuource,将application.yml放进来

  2. 新建Application

    package com.wpj.homepage;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    /**
     * 测试用例启动入口
     */
    @EnableFeignClients(basePackages = {"com.wpj.homepage"})
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    
  3. 新建ServiceTest

    package com.wpj.homepage.service;
    
    import com.alibaba.fastjson.JSON;
    import com.wpj.homepage.Application;
    import com.wpj.homepage.dao.HomepageUserCourseDao;
    import com.wpj.homepage.entity.HomepageUserCourse;
    import com.wpj.homepage.vo.CreateUserRequest;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.Arrays;
    
    /**
     * 用户服务测试
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {Application.class})
    public class HomepageUserServiceTest {
    
        @Autowired
        private IUserService userService;
    
        @Autowired
        private HomepageUserCourseDao userCourseDao;
    
        @Test
        @Transactional
        public void testCreateUser() {
    
            System.out.println(JSON.toJSONString(userService.createUser(
                    new CreateUserRequest("wpj", "wpj@imooc.com")
            )));
        }
    
        @Test
        public void testGetUser() {
    
            System.out.println(JSON.toJSONString(userService.getUserInfo(2L)));
        }
    
        @Test
        public void testCreateHomepageUserCourse() {
    
            HomepageUserCourse course1 = new HomepageUserCourse();
            course1.setUserId(6L);
            course1.setCourseId(6L);
    
            HomepageUserCourse course2 = new HomepageUserCourse();
            course2.setUserId(6L);
            course2.setCourseId(7L);
    
            System.out.println(userCourseDao.saveAll(Arrays.asList(course1, course2)).size());
        }
    }
    

8. 测试对外服务接口

8.1 homepage-zuul的application.yml

zuul:
  prefix: /wpj
  routes:
    course:
      path: /homepage-course/**
      serviceId: eureka-client-homepage-course
      strip-prefix: false
    user:
      path: /homepage-user/**
      serviceId: eureka-client-homepage-user
      strip-prefix: false

8.2 运行EurakeApplication和ZuulApplication

在这里插入图片描述

8.3 测试对外服务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值