SpringCloud分布式项目集成了一些常用框架及插件 内含源码

SpringBoot集成mybatis+PegeHelper分页插件+redis+kafka+SpringCloud(Swagger2+Feign)+shiro权限框架(分布式项目 内含源码)

源码网盘下载地址:https://pan.baidu.com/s/1QEeIGrMC1Rc9ScCaOsbIhw
提取码:488z

虽然现在SprignBoot很火,但由于本人任职的几家公司项目都是采用常规的SSM框架搭建,再加上现在的工作偏向于前端一点,所以实际项目中一直都没有用到,正好这几天没啥事就想着利用公司的开发环境学习学习,在网上看了看资料整了一个小demo,现在整理了一下发出来,毕竟也是初学,有出入的地方还望各位大佬谅解。

一. 新建一个SpringBoot项目
1.创建一个maven工程项目
2.添加maven依赖

	<!-- 定义spring-boot的版本 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath></relativePath>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<!-- jdk版本 -->
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>jdk.tools</groupId>
			<artifactId>jdk.tools</artifactId>
			<version>1.8</version>
			<scope>system</scope>
			<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
		</dependency>
		<!-- spring-boot的web启动的核心jar包 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>
	
	<!--maven的插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
		<!-- 配置java版本 不配置的话默认父类配置的是1.6 -->
		<pluginManagement>
			<plugins>
				<plugin>
					<artifactId>maven-compiler-plugin</artifactId>
					<configuration>
						<source>1.8</source>
						<target>1.8</target>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

3.创建入口类Application,加上@SpringBootApplication注解。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * @author Jun
 * @version 创建时间:2019年2月21日 上午10:40:04 
 * 类说明		SpringBoot启动类
 */
@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

4.创建测试类TestController。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 上午11:30:53 
 * 类说明
 */
@Controller
public class TestController {
	@ResponseBody
	@RequestMapping("/")
	public String test() {
		return "true";
	}
}

5.在入口类Application中启动项目,启动成功如下图。
在入口类Application中启动项目
6.打开浏览器输入http://localhost:8080/,测试成功。(application配置文件不配置服务端口,SpringBoot默认为8080端口)。
测试
7.添加SpringBoot的配置文件application.properties,配置服务访问端口号。(SpringBoot有properties和yml2种配置方式,文件名必须为application,SpringBoot加载是会默认读取application文件下的配置)
application.properties配置文件
二. SpringBoot整合mybatis。
1.添加maven依赖

		<!--mysql驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!-- 阿里系的Druid依赖包 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.9</version>
		</dependency>
		<!-- Druid 依赖 log4j包 -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<!--jpa的jar包 ,操作数据库的,类似hibernate -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<!-- spring-boot整合mybatis -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
		<!-- lombok 简写代码  可用注解代替get set等 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

2.创建entity、service、dao。
(1)User实体类

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* @author Jun
* @version 创建时间:2019年2月21日 上午11:40:58
* 类说明  用户实体类
*/
@Getter
@Setter
@ToString
public class User implements Serializable{

	private static final long serialVersionUID = 1L;
	
	private String loginName;
	private String password;
	
}

(2)Mapper接口

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.jwu.demo.entity.User;
/**
* @author Jun
* @version 创建时间:2019年2月21日 上午11:44:07
* 类说明
*/
@Mapper
public interface UserMapper {

	List<User> getAll();

}

(3)Service接口

import java.util.List;
import com.jwu.demo.entity.User;

/**
* @author Jun
* @version 创建时间:2019年2月21日 上午11:42:14
* 类说明	
*/
public interface IUserService {

	List<User> getAll();

}

(4)Service实现类

import java.util.List;

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

import com.jwu.demo.dao.UserMapper;
import com.jwu.demo.entity.User;
import com.jwu.demo.service.IUserService;
/**
* @author Jun
* @version 创建时间:2019年2月21日 上午11:43:04
* 类说明
*/
@Service
public class UserServiceImpl implements IUserService {
	
	@Autowired
	private UserMapper userMapper;

	public List<User> getAll() {
		return userMapper.getAll();
	}
	
}

3.在application.properties配置文件中添加数据源以及mybatis的配置。

#数据源
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.0.37:3306/dwqmain?createDatabaseIfNotExist=true&amp;useUnicode=true&amp;characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456

#阿里druid连接池驱动配置信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#连接池的配置信息
#初始化大小,最小,最大
spring.datasource.initialSize=2
spring.datasource.minIdle=2
spring.datasource.maxActive=3
#配置获取连接等待超时的时间
spring.datasource.maxWait=6000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
#打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

#mybatis配置
#配置Mapper文件存放的路径  
mybatis.mapper-locations=classpath:mapper/*Mapper.xml	
#对应实体类所在的包  
mybatis.typeAliasesPackage=com.juwu.demo.entity

4.在resources下新建mapper文件夹,然后创建UserMapper的接口映射文件UserMapper.xml。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.jwu.demo.dao.UserMapper">

	<select id="getAll" resultType="User">
		select 
			login_name 		loginName,
			user_name		userName		
		from 
			bmc_user
	</select>
	
</mapper>

5.在TestController中添加测试方法。

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.jwu.demo.entity.User;
import com.jwu.demo.service.IUserService;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 上午11:30:53 
 * @类说明	测试
 */
@Controller
public class TestController {
	
	@Autowired
	private IUserService userService;

	@ResponseBody
	@RequestMapping("/")
	public List<User> test() {
		return userService.getAll();
	}

}

6.启动Application入口类,在浏览器输入http://localhost:8888/,json数据成功返回,整合mybaties成功。
测试
三. 整合PegeHelper分页插件。
   使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,最后还需要自己在后台进行分页封装,PegeHelper分页插件完美的解决了这些问题。(由于PegeHelper利用了mybatis提供的拦截器,取得ThreadLocal的值,重新拼装的分页SQL完成的分页,所以在大数据量时,不利于sql的优化处理,公司有个项目当时一个分页sql 一张200多万数据的表关联2张表足足查询了20多秒,简直不能忍受,最后还是自己优化sql重新封装的分页)。
  
1.添加pagehelper分页的maven依赖。

<!-- pagehelper分页 -->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper-spring-boot-starter</artifactId>
	<version>1.2.5</version>
</dependency>

2.在application配置文件中添加pagehelper的配置信息。

#pagehelper分页插件
pagehelper.helperDialect: mysql
pagehelper.reasonable: true
pagehelper.supportMethodsArguments: true
pagehelper.params: count=countSql
pagehelper.returnPageInfo: check

3.配置完成,在TestController中进行测试。

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwu.demo.entity.User;
import com.jwu.demo.service.IUserService;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 上午11:30:53 类说明
 */
@Controller
public class TestController {
	
	@Autowired
	private IUserService userService;

	@ResponseBody
	@RequestMapping("/")
	public PageInfo<User> test() {
		PageHelper.startPage(1, 10);
		List<User> userList = userService.getAll();
		PageInfo<User> pageInfo = new PageInfo<>(userList);
		return pageInfo;
	}

}

4.浏览器访问http://localhost:8888/,返回json数据如下图。
测试返回json数据
四. 集成redis。
1.添加redismaven依赖

<!-- redis -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring2.0集成redis所需common-pool2-->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
</dependency>

2.在application配置文件中添加redis配置信息。

#redis
spring.redis.database=0
spring.redis.host=192.168.0.92
spring.redis.port=6377
spring.redis.password=juwudwq123!
spring.redis.timeout=5000
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-wait=5000
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=5

3.创建Redis服务接口以及实现类。
(1)IRedisService

/**
* @author Jun
* @version 创建时间:2019年2月22日 下午5:29:59
* 类说明	
*/
public interface IRedisService {

	void setValue(String key,Object value);
	
	/**
	 * 通过redis获取redis中的key
	 * @param key
	 * @return
	 */
	Object getValue(String key);
	
	/**
	 * 存入redis并设置有效期
	 * @param key
	 * @param value
	 * @param exceed	有效期
	 * @param timeType 	0:按天,1:按时,2:按分,3:按秒,4:按毫秒
	 */
	void setValue(String key,Object value,Integer exceed,Integer timeType);
	
}

(2)RedisServiceImpl

import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.jwu.demo.service.IRedisService;
/**
* @author Jun
* @version 创建时间:2019年2月22日 下午5:30:19
* 类说明	Redis服务
*/
@Service
public class RedisServiceImpl implements IRedisService {

	@Autowired
	private RedisTemplate redisTemplate;

	@SuppressWarnings("unchecked")
	@Override
	public void setValue(String key,Object value) {
		redisTemplate.opsForValue().set(key, value);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Object getValue(String key) {
		if(!redisTemplate.hasKey(key)){
    		return null;
    	}else{
    		return redisTemplate.opsForValue().get(key);
    	}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void setValue(String key, Object value, Integer exceed, Integer timeType) {
		switch (timeType) {
		case 0://天
			redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.DAYS);
			break;
		case 1://小时
			redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.HOURS);		
			break;
		case 2:	//分钟
			redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.MINUTES);
			break;
		case 3:	//秒
			redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.SECONDS);
			break;
		case 4://毫秒 
			redisTemplate.opsForValue().set(key, value, exceed, TimeUnit.MICROSECONDS);
			break;
		}
	}
}

4.测试代码。

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwu.demo.entity.User;
import com.jwu.demo.service.IRedisService;
import com.jwu.demo.service.IUserService;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 上午11:30:53 类说明
 */
@Controller
public class TestController {
	
	@Autowired
	private IUserService userService;
	@Autowired
	private IRedisService redisService;

	@ResponseBody
	@RequestMapping("/")
	public PageInfo<User> test() {
		PageHelper.startPage(1, 10);
		List<User> userList = userService.getAll();
		PageInfo<User> pageInfo = new PageInfo<>(userList);
		
		//存入redis并设置10秒的有效期
		redisService.setValue("redisKey", pageInfo, 3, 3);
		System.out.println("redisKey的值 ----------------》 " + redisService.getValue("redisKey"));
		try {
			Thread.sleep(3000);
			System.out.println("redisKey 睡眠3秒后的值 ----------》 " + redisService.getValue("redisKey"));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return pageInfo;
	}
	
}

5.测试结果。
测试结果
五.集成kafka消息队列
1.添加kafka maven依赖。

<!-- kafka -->
		<dependency>
			<groupId>org.springframework.kafka</groupId>
			<artifactId>spring-kafka</artifactId>
		</dependency>
		<!-- fastjson -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>
		<!-- lang字符串工具 -->
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>

2.在application配置文件中添加kafka配置信息。

#kafka
spring.applicationname=kafka-tutorial
# 指定kafka 代理地址,可以多个
spring.kafka.bootstrap-servers=192.168.0.167:9092
spring.kafka.producer.retries: 0
# 每次批量发送消息的数量
spring.kafka.producer.batch-size: 16384
# 缓存容量
spring.kafka.producer.buffer-memory: 33554432
# 指定消息key和消息体的编解码方式
spring.kafka.producer.key-serializer: org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer: org.apache.kafka.common.serialization.StringSerializer
# 指定默认消费者group id
spring.kafka.consumer.group-id=demo
spring.kafka.consumer.auto-commit-interval=100
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.enable-auto-commit=true
# 指定消息key和消息体的编解码方式
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
# 指定listener容器中的线程数,用于提高并发量
spring.kafka.listener.concurrency=3

3.新建bean包,创建kafka生产者与消费者。
(1)生产者KafkaProduction

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

import com.alibaba.fastjson.JSON;

/**
* @author Jun
* @version 创建时间:2019年2月22日 下午3:59:44
* 类说明		Kafka生产者
*/
@Component
public class KafkaProduction<T> {

    private Logger logger = LoggerFactory.getLogger(KafkaProduction.class);

    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;

    /**
     * 发送消息
     * @param obj	消息体
     * @param topics  消息主题
     */
    public void send(T obj,String topics) {
        String jsonObj = JSON.toJSONString(obj);
        logger.info("----kafka---- message = {}", jsonObj);
        //发送消息
        ListenableFuture<SendResult<String, Object>> future = kafkaTemplate.send(topics, jsonObj);
        future.addCallback(new ListenableFutureCallback<SendResult<String, Object>>() {
            @Override
            public void onFailure(Throwable throwable) {
                logger.info("KafkaProduction: The message failed to be sent:" + throwable.getMessage());
            }

            @Override
            public void onSuccess(SendResult<String, Object> stringObjectSendResult) {	//成功消费
                //TODO 业务处理
                logger.info("KafkaProduction: The message was sent successfully:");
                logger.info("KafkaProduction: _+_+_+_+_+_+_+ result: " + stringObjectSendResult.toString());
            }
        });
    }
}

(2)消费者KafkaConsumer。

import java.util.Optional;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

import com.jwu.demo.constant.KafkaTopicsConstant;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 下午4:12:26 类说明 Kafka消费者
 */
@Component
public class KafkaConsumer {

	private Logger logger = LoggerFactory.getLogger(KafkaConsumer.class);
	
	/**
     * 监听kafka.tut 的topic为test_topics的消息
	 * @param record
	 */
	@KafkaListener(topics = KafkaTopicsConstant.TEST_TOPICS)
	public void listen(ConsumerRecord<?, ?> record) {
		Optional<?> kafkaMessage = Optional.ofNullable(record.value());

		if (kafkaMessage.isPresent()) {
			Object message = kafkaMessage.get();
			logger.info("KafkaConsumer  Receive: +++++++++++++++ Topic:" + record.topic());
			logger.info("KafkaConsumer  Receive: +++++++++++++++ Record:" + record);
			logger.info("KafkaConsumer  Receive: +++++++++++++++ Message:" + message);
		}
	}

}

(3)KafkaTopicsConstant常量类

/**
* @author Jun
* @version 创建时间:2019年2月22日 下午4:37:57
* 类说明
*/
public class KafkaTopicsConstant {
	
	/**kafka测试消息主题名*/
	public final static String TEST_TOPICS = "test_topics";
	
}

(4)IKafkaSenderService
/**
* @author Jun
* @version 创建时间:2019年2月22日 下午4:09:36
* 类说明
*/
public interface IKafkaSenderService {
	
	/**
	 * 发送主题为test_topics的消息
	 */
	public void send();
	
}

(5)KafkaSenderServiceImpl

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

import com.jwu.demo.bean.KafkaProduction;
import com.jwu.demo.constant.KafkaTopicsConstant;
import com.jwu.demo.entity.User;
import com.jwu.demo.service.IKafkaSenderService;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 下午4:09:49 类说明
 */
@Service
public class KafkaSenderServiceImpl implements IKafkaSenderService {

	@Autowired
	private KafkaProduction<User> kafkaProduction;

	@Override
	public void send() {
		User user = new User();
		user.setLoginName("szjuwu");
		user.setPassword("123456");
		kafkaProduction.send(user,KafkaTopicsConstant.TEST_TOPICS);
	}

}

4.测试代码。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.jwu.demo.service.IKafkaSenderService;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 上午11:30:53 类说明
 */
@Controller
public class TestController {
	
	@Autowired
	private IKafkaSenderService kafkaSenderService;

	@ResponseBody
	@RequestMapping("/")
	public void test() {
		kafkaSenderService.send();
	}
	
}

5.运行结果。
运行结果
六.集成SpringCloud。

  1. 搭建eruka服务。
    (1)新建一个maven工程项目,添加eruka依赖。新建一个maven工程项目,添加eruka依赖。
<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Brixton.RELEASE</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
 
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
		</dependency>
	</dependencies>

	<!--maven的插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

(2)在resources下新建application.properties配置文件。

server.port=8088

# 不向注册中心注册自己
eureka.client.register-with-eureka=false
# 不需要检索服务
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/

(3)新建入口类Application并启动。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author Jun
 * @version 创建时间:2019年2月21日 上午10:40:04 类说明
 */
@EnableEurekaServer
@SpringBootApplication
public class Application {
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

(4)在浏览器中输入http://localhost:8088,Eureka注册中心搭建完成。
Eureka
2.搭建服务端提供者。(直接在最开始项目的基础上面做修改)。
(1)添加maven依赖。

<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.RELEASE</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	
	<!-- SpringCloud start -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
		<!-- SpringCloud end -->

(2)在application配置文件中添加eureka配置信息。

#服务名称
spring.application.name=demo-server
##服务注册和发现中心
eureka.client.serviceUrl.defaultZone=http://localhost:8088/eureka

(3)在application入口类@EnableDiscoveryClient、@EnableCircuitBreaker、@EnableFeignClients添加注解并启动。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @author Jun
 * @version 创建时间:2019年2月21日 上午10:40:04 类说明
 */
@EnableDiscoveryClient  
@EnableCircuitBreaker  
@EnableFeignClients
@SpringBootApplication
public class Application {
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

(4)先启动eureka服务,再启动demo-server,输入http://localhost:8088/,下图表示demo-server服务已成功注册在eureka上。
demo-server注册成功
3.服务端集成Swagger2,方便开发人员接口的对接与调式。
(1)在pom.xml中加入Swagger2的依赖

	<!-- swagger start -->
		<dependency>
		    <groupId>io.springfox</groupId>
		    <artifactId>springfox-swagger2</artifactId>
		    <version>2.2.2</version>
		</dependency>
		<dependency>
		    <groupId>io.springfox</groupId>
		    <artifactId>springfox-swagger-ui</artifactId>
		    <version>2.2.2</version>
		</dependency>
		<!-- swagger end -->

(2)在Application.java同级包下创建Swagger2的配置类Swagger2。通过@Configuration注解,让Spring来加载该类配置。再通过@EnableSwagger2注解来启用Swagger2。
在这里插入图片描述

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author Jun
 * @version 创建时间:2019年2月27日 下午5:46:47 类说明
 */
@Configuration
@EnableSwagger2
public class Swagger2 {
	@Bean
	public Docket createRestApi() {
		return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
				.apis(RequestHandlerSelectors.basePackage("com.jwu.demo"))
				.paths(PathSelectors.any()).build();
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder().title("Spring Cloud demo API文档")// 标题
				.version("1.0.0") // 版本
				.build();
	}
}

(3)创建SwaggerController类进行测试。

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.jwu.demo.entity.User;
import com.jwu.demo.service.IUserService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
* @author Jun
* @version 创建时间:2019年2月27日 下午6:00:59
* 类说明
*/
@Api(tags = "Swagger测试",produces = MediaType.APPLICATION_JSON_VALUE)
@RestController
@RequestMapping(value = "/swagger", produces = MediaType.APPLICATION_JSON_VALUE)
public class SwaggerController {
	
	@Autowired
	private IUserService userService;
	
	@ApiOperation(value = "获取所有用户信息", notes = "获取所有用户信息")
    @RequestMapping(value = "/getAll", method = RequestMethod.GET)
	public List<User> getFansPage() {
    	return userService.getAll();
	}
	
}

(4)启动erueka服务和demo-server服务,在浏览器中输入http://localhost:8888/swagger-ui.html#访问。
在这里插入图片描述
在这里插入图片描述
4.搭建客户端消费。(使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务)。
(1)新建一个SpringBoot项目,这里就直接上代码了。
maven依赖

<!-- spring-boot的父引用 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath></relativePath>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
		<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
	</properties>

	<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>jdk.tools</groupId>
			<artifactId>jdk.tools</artifactId>
			<version>1.8</version>
			<scope>system</scope>
			<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<!--热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
		<!--web支持 依赖 -->
		<!-- SpringCloud start -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringCloud end -->
		<!-- lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<!--maven的插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

application.properties配置文件

spring.application.name=demo-web
server.port=8080

#eureka注册中心发现地址
eureka.client.service-url.defaultZone=http://localhost:8088/eureka
eureka.instance.appname=demo-web

Application启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @author Jun
 * @version 创建时间:2019年2月21日 上午10:40:04 类说明
 */
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application {
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

新建一个UserRemote类利用Feign调用服务端的接口

import java.util.List;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.juwu.demo.web.entity.User;

import feign.Headers;

/**
* @author Jun
* @version 创建时间:2019年2月27日 下午8:27:40
* 类说明
*/
@FeignClient(name = "demo-server")
@Headers("Content-Type: application/json;charset=UTF-8")
public interface UserRemote {
	
	@RequestMapping(value="/swagger/getAll", method=RequestMethod.GET)
    List<User> getAll();

}

User实体类

import java.io.Serializable;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
* @author Jun
* @version 创建时间:2019年2月21日 上午11:40:58
* 类说明
*/
@Getter
@Setter
@ToString
public class User implements Serializable{
	
	private static final long serialVersionUID = 1L;

	private String loginName;
	
	private String password;
	
}

LoginController

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.juwu.demo.web.entity.User;
import com.juwu.demo.web.remote.UserRemote;

/**
* @author Jun
* @version 创建时间:2019年2月27日 下午6:44:29
* 类说明
*/
@Controller
public class LoginController {
	
	@Autowired
	private UserRemote userRemote;
	
	@RequestMapping("/getAll")
	@ResponseBody
	public List<User> getAll() {
		List<User> userList = userRemote.getAll();
		return userList;
	}
	
}

依次启动Eureka注册中心、服务端服务、客户端项目,在浏览器输入http://localhost:8080/getAll,远程调用成功,返回JSON数据。

七.集成shiro权限框架
由于现有数据库没有角色、权限等表,加上没有整合前端页面,故这里只做登录测试,如果要进行权限认证的话,还需在页面添加对应Shiro权限标签。(在页面上加shiro标签的时候,shiro会调用doGetAuthorizationInfo方法判断当前用户有没有这个权限)。

<!-- shiro整合springboot所需相关依赖-->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
		
		<dependency>
		    <groupId>commons-codec</groupId>
		    <artifactId>commons-codec</artifactId>
		</dependency>
		<!-- log4j -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>

2.自定义一个UserRealm类继承AuthorizingRealm,获取Shiro应用配置Realm中的用户及其权限信息。

import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.juwu.demo.web.entity.User;
import com.juwu.demo.web.utils.Md5Util;

/**
* @author Jun
* @version 创建时间:2019年2月22日 上午11:12:33
* 类说明	
*/
@Component
public class UserRealm extends AuthorizingRealm {
	
	public static final Logger logger = LoggerFactory.getLogger(UserRealm.class);
 
	 /**
	  * 用户角色和权限授权
	  */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection Principal){
		String loginName = (String) Principal.getPrimaryPrincipal();
		SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
		try {
			//获取当前登录用户的所有角色以及权限存入shiro去做权限认证
			/*
			 Set<String> roleName = userService.getRoleName(loginName); //获取登录用户的所有角色
			Set<String> permissions = userService.getPermissions(loginName); //获取登录用户的所有权限
			authorizationInfo.setRoles(roleName);
			authorizationInfo.setStringPermissions(permissions);*/
		} catch (Exception e) {
			logger.error("UserRealm doGetAuthorizationInfo",e);
		}
		logger.info("authorizationInfo : {}" + authorizationInfo);
		return authorizationInfo;
	}
   
	/**
	 * 用户身份登陆认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		String loginName = token.getUsername();	//获取登录的用户名
		logger.info("doGetAuthenticationInfo loginName --------->:" + loginName);
		try {
			//根据登录名获取用户信息
			//User user = userService.getByLoginName(loginName);
			
			//构造user测试数据
			User user = new User();
			user.setLoginName("szjuwu");
			user.setPassword(Md5Util.MD5("123456"));
			
			if(user != null){
				AuthenticationInfo authcInfo= new SimpleAuthenticationInfo(user.getLoginName(),user.getPassword(),getName());
				return authcInfo;
			}
		} catch (Exception e) {
			logger.error("UserRealm doGetAuthenticationInfo ============ 身份认证失败",e);
		}
		return null;
	}
 
}

3.创建ShiroConfig配置类。

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.juwu.demo.web.bean.UserRealm;

import org.apache.shiro.mgt.SecurityManager;

/**
* @author Jun
* @version 创建时间:2019年2月22日 下午1:41:43
* 类说明
*/
@Configuration
public class ShiroConfig {
	
	@Autowired
    private UserRealm userRealm;
    /**
     * 配置shiro过滤器
     * @author zhengkai
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager securityManager) {
        //1.定义shiroFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        //2.设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //3.LinkedHashMap是有序的,进行顺序拦截器配置
        Map<String,String> filterChainMap = new LinkedHashMap<String,String>();
        //4.配置logout过滤器
        filterChainMap.put("/logout", "logout");
        //登陆和主页不需要认证
        filterChainMap.put("/login","anon");
        filterChainMap.put("/","anon");
        filterChainMap.put("/checkLogin","anon");
        filterChainMap.put("/css/**", "anon"); //匿名访问静态资源
        filterChainMap.put("/js/**", "anon"); //匿名访问静态资源
        filterChainMap.put("/fonts/**", "anon"); //匿名访问静态资源
        filterChainMap.put("/images/**", "anon"); //匿名访问静态资源
        filterChainMap.put("/lib/**", "anon"); //匿名访问静态资源
 
        //5.所有url必须通过认证才可以访问
        filterChainMap.put("/**","authc");
 
        //6.设置默认登录的url
        shiroFilterFactoryBean.setLoginUrl("/login");
        //7.设置成功之后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/getAll");
        //8.设置未授权界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        //9.设置shiroFilterFactoryBean的FilterChainDefinitionMap
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return shiroFilterFactoryBean;
    }
    /**
     * 配置安全管理器
     * @author zhengkai
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(userRealm);//将自定义的realm注入到securityManager中
        return securityManager;
    }
 
}

4.MD5工具类。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import org.apache.commons.codec.binary.Hex;

/**
 * @author Jun
 * @version 创建时间:2019年2月22日 上午11:37:06 类说明
 */
public class Md5Util {

	/**
	 * 普通MD5
	 * 
	 * @author daniel
	 * @time 2016-6-11 下午8:00:28
	 * @param inStr
	 * @return
	 */
	public static String MD5(String input) {
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			return "check jdk";
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
		char[] charArray = input.toCharArray();
		byte[] byteArray = new byte[charArray.length];

		for (int i = 0; i < charArray.length; i++)
			byteArray[i] = (byte) charArray[i];
		byte[] md5Bytes = md5.digest(byteArray);
		StringBuffer hexValue = new StringBuffer();
		for (int i = 0; i < md5Bytes.length; i++) {
			int val = ((int) md5Bytes[i]) & 0xff;
			if (val < 16)
				hexValue.append("0");
			hexValue.append(Integer.toHexString(val));
		}
		return hexValue.toString();
	}
	
	 /** 
     * 文件的MD5 
     * @param filePath 
     * @return 
     */  
    public static String getFileMD5(String filePath){  
        String value = null;  
        FileInputStream in = null;  
        try {  
            File file = new File(filePath);  
            in = new FileInputStream(file);  
            MessageDigest md5 = MessageDigest.getInstance("MD5");  
            byte[] buffer = new byte[8192];  
            int c;  
            while ((c = in.read(buffer)) != -1) {  
                md5.update(buffer, 0, c);  
            }  
            BigInteger bi = new BigInteger(1, md5.digest());  
            value = bi.toString(16).toUpperCase();  
        } catch (Exception e) {  
        	
        } finally {  
            if (null != in) {  
                try {  
                    in.close();  
                } catch (IOException e) {  
                	
                }  
            }  
        }  
        return value;  
    }  

	/**
	 * 加盐MD5
	 * 
	 * @author daniel
	 * @time 2016-6-11 下午8:45:04
	 * @param password
	 * @return
	 */
	public static String generate(String password) {
		Random r = new Random();
		StringBuilder sb = new StringBuilder(16);
		sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
		int len = sb.length();
		if (len < 16) {
			for (int i = 0; i < 16 - len; i++) {
				sb.append("0");
			}
		}
		String salt = sb.toString();
		password = md5Hex(password + salt);
		char[] cs = new char[48];
		for (int i = 0; i < 48; i += 3) {
			cs[i] = password.charAt(i / 3 * 2);
			char c = salt.charAt(i / 3);
			cs[i + 1] = c;
			cs[i + 2] = password.charAt(i / 3 * 2 + 1);
		}
		return new String(cs);
	}

	/**
	 * 校验加盐后是否和原文一致
	 * 
	 * @author daniel
	 * @time 2016-6-11 下午8:45:39
	 * @param password
	 * @param md5
	 * @return
	 */
	public static boolean verify(String password, String md5) {
		char[] cs1 = new char[32];
		char[] cs2 = new char[16];
		for (int i = 0; i < 48; i += 3) {
			cs1[i / 3 * 2] = md5.charAt(i);
			cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
			cs2[i / 3] = md5.charAt(i + 1);
		}
		String salt = new String(cs2);
		return md5Hex(password + salt).equals(new String(cs1));
	}

	/**
	 * 获取十六进制字符串形式的MD5摘要
	 */
	private static String md5Hex(String src) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			byte[] bs = md5.digest(src.getBytes());
			return new String(new Hex().encode(bs));
		} catch (Exception e) {
			return null;
		}
	}

	public static void main(String[] args) {
		String md5 = MD5("123456");
		System.out.println(md5);
	}
	
}

5.在LoginController中添加login方法。

@RequestMapping("/login")
@ResponseBody
public String chkUser(User user,Model model){
		if (user != null && StringUtils.isNotBlank(user.getLoginName()) 
				&& StringUtils.isNotBlank(user.getPassword())) {
			Subject subject = SecurityUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(user.getLoginName(), Md5Util.MD5(user.getPassword()));
			try {
				subject.login(token);// 会跳到我们自定义的realm中
				subject.getSession().setAttribute("user", user);
				logger.info(user.getLoginName() + "登录成功");
				return "true";
			} catch (AuthenticationException a) {
				logger.warn(user.getLoginName() + "登陆系统,身份认证失败!" + 
						new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			}
		}
		return "false";
	}

6.依次启动Eureka注册中心、服务端服务、客户端项目,在浏览器直接输入http://localhost:8080/getAll,因为没登录被shiro拦截跳转到了刚刚配置的login路径下。
在这里插入图片描述
7.先在浏览器输入http://localhost:8080/login?loginName=szjuwu&password=123456进行登录。
在这里插入图片描述
8.登入成功后,再输入http://localhost:8080/getAll,发现这次没有被shiro拦截,成功返回数据。
在这里插入图片描述
OK,搞定。

猜你喜欢

转载自blog.csdn.net/qq_42258587/article/details/88019560