SpringBoot学习总结

目录

1、我的第一个SpringBoot项目

创建SpringBoot项目

如何修改端口号

2、SpringBoot自动装配原理

3、yaml语法

用yaml赋值

配置文件占位符?

结论:

4、JSR303数据校验及多环境切换

5、整合JDBC,Druid,Mybatis

1.整合JDBC

2.整合Druid

3.整合Mybatis

6、SpringSecurity

实验环境搭建

认识SpringSecurity

认证和授权

1.引入 Spring Security 模块

2.编写 Spring Security 配置类

权限控制和注销

1.开启自动配置的注销的功能

2.在前端中添加一个注销按钮?

3.其他功能实现

记住我

定制登录页

7、Shiro

1.springboot整合shiro环境搭建

2.shiro实现登录拦截

3.Shiro实现用户认证?

4.Shiro整合Mybatis

5.Shiro请求授权实现

6.Shiro整合thymeleaf

8、Swagger

1.SpringBoot集成Swagger

2.配置Swagger

3.配置扫描接口

4.配置Swagger开关

5.配置API分组

6.实体配置

7.常用注解

9、异步、定时、邮件任务

1.异步任务

2.定时任务

3.邮件任务

10、Dubbo&Zookeeper

1.Dubbo

2.Dubbo+Zookeeper环境搭建

Zookeeper

Dubbo

3.SpringBoot+Dubbo+Zookeeper

服务提供者

服务消费者

启动测试


1、我的第一个SpringBoot项目

创建SpringBoot项目

选择导入的依赖,完成即可构建成功!

测试一下

启动springboot

成功访问

如何修改端口号

修改后重启

8080无响应

8081可以访问

2、SpringBoot自动装配原理

3、yaml语法

用key:空格 value表示

用yaml赋值

实体类。使用@ConfigurationProperties注解要导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

yaml文件中进行对实体类的赋值,birth一定要注意格式

测试类和测试结果

property赋值

测试结果

配置文件占位符

配置文件还可以编写占位符生成随机数

对比:

@Value这个使用起来并不友好,我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比图

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

2、松散绑定:这个什么意思呢 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下

3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性

4、复杂类型封装,yml中可以封装对象 , 使用value就不支持

结论:

配置yml和配置properties都可以获取到值 , 强烈推荐 yml;

如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;

如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫!

4、JSR303数据校验及多环境切换

Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式;

运行会直接报错

使用数据校验,可以保证数据的正确性;

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 Date 和 Calendar 对象是否在当前时间之前  
@Future     验证 Date 和 Calendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

.......等等
除此以外,我们还可以自定义一些数据校验规则

5、整合JDBC,Druid,Mybatis

1、整合JDBC

application.yml文件中配置JDBC

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

2、整合Druid

导入依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

Druid数据源的yml配置

    #SpringBoot默认是不注入这些的,需要自己绑定
    #druid数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Properity
    #则导入log4j 依赖就行
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

设置一个后台监控

@Configuration
public class DruidConfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }

    //后台监控 : web,xml, ServletRegistrationBean
    //因为SpringBoot内置了servlet容器,所以没有web.xml,替代方法 ServletRegistrationBean
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");

        //后台需要有人登录,账号密码配置
        HashMap<String, String> initParameters = new HashMap<>();

        //增加配置
        initParameters.put("loginUsername","admin");//登录key 是固定的  loginUsername loginPassword
        initParameters.put("loginPassword","123456");

        //允许谁可以访问
        initParameters.put("allow","");//参数为空,所有人都可以访问

        //禁止谁能访问    initParameters.put("lqh","192.168.1.1");

        bean.setInitParameters(initParameters);//设置初始化参数
        
        return bean;
    }
}

登录访问localhost:8080/druid

设置一个简单的过滤器

    //filter过滤器
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();

        bean.setFilter(new WebStatFilter());

        //可以过滤哪些请求
        Map<String,String> initParameters = new HashMap<>();
        //这些东西不进行统计
        initParameters.put("exclusions","*.js,*.css,/druid/*");

        bean.setInitParameters(initParameters);

        return bean;
    }

3、整合Mybatis

实体类

mapper接口

在resources下新建mybatis/mapper/UserMapper.xml 来存放xml文件

application.properties配置mybatis的配置信息

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#整合mybatis
mybatis.type-aliases-package=com.lqh.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

Controller层

6、SpringSecurity

实验环境搭建

1、新建一个初始的springboot项目web模块,thymeleaf模块

2、导入静态资源

3、controller跳转

认识SpringSecurity

Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理!

记住几个类:

  • WebSecurityConfigurerAdapter:自定义Security策略

  • AuthenticationManagerBuilder:自定义认证策略

  • @EnableWebSecurity:开启WebSecurity模式

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。

“认证”(Authentication)

身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。

身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。

“授权” (Authorization)

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

这个概念是通用的,而不是只在Spring Security 中存在。

认证和授权

目前,我们的测试环境,是谁都可以访问的,我们使用Spring Security增加上认证和授权的功能

1、引入 Spring Security 模块

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

2、编写 Spring Security 配置类

@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人都可以访问,功能页面只有对应有权限的人才能访问
        //权限授权规则
        http.authorizeRequests().antMatchers("/").permitAll()
                                .antMatchers("/level1/**").hasRole("vip1")
                                .antMatchers("/level2/**").hasRole("vip2")
                                .antMatchers("/level3/**").hasRole("vip3");

        //没有权限会默认到登录页面
        http.formLogin();
    }

    //认证

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //在内存中定义,也可以在jdbc中去拿
        //Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
        //要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
        //spring security 官方推荐的是使用bcrypt加密方式。
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("liuqianhao").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and()
                .withUser("liangzhu").password(new BCryptPasswordEncoder().encode("123456")).roles("vip3");
    }
}

权限控制和注销

1、开启自动配置的注销的功能

2、在前端中添加一个注销按钮

                <a class="item" th:href="@{/logout}">
                    <i class="sign-out icon"></i> 注销
                </a>

3、其他功能实现

导入maven依赖

<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
   <groupId>org.thymeleaf.extras</groupId>
   <artifactId>thymeleaf-extras-springsecurity5</artifactId>
   <version>3.0.4.RELEASE</version>
</dependency>

修改我们的 前端页面

导入命名空间

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"

修改导航栏,增加认证判断

如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能;我们试试:在 配置中增加 http.csrf().disable();

        //开启自动配置的注销的功能
        // /logout 注销请求
        http.logout().logoutSuccessUrl("/");
        //关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
        http.csrf().disable();

继续将下面的角色功能块认证完成

测试一下就搞定了

记住我

现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单

开启记住我功能

 //记住我
   http.rememberMe();

定制登录页

现在这个登录页面都是spring security 默认的,怎么样可以使用我们自己写的Login界面呢?

1.在刚才的登录页配置后面指定 loginpage

http.formLogin().loginPage("/toLogin");

2.然后前端也需要指向我们自己定义的 login请求

<a class="item" th:href="@{/toLogin}">
   <i class="address card icon"></i> 登录
</a>

3.我们登录,需要将这些信息发送到哪里,我们也需要配置,login.html 配置提交请求及方式,方式必须为post

4、这个请求提交上来,我们还需要验证处理,怎么做呢?我们可以查看formLogin()方法的源码!我们配置接收登录的用户名和密码的参数

http.formLogin()
  .usernameParameter("username")
  .passwordParameter("password")
  .loginPage("/toLogin")
  .loginProcessingUrl("/login"); // 登陆表单提交请求

5、在登录页增加记住我的多选框

<input type="checkbox" name="remember"> 记住我

6、后端验证处理

//定制记住我的参数!
http.rememberMe().rememberMeParameter("remember");

7、Shiro

1、springboot整合shiro环境搭建

1.新建一个springboot模块

2.添加maven依赖

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.8.0</version>
        </dependency>

3.编写首页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>首页</h1>

<p th:text="${msg}"></p>

</body>
</html>

4.编写controller

@Controller
public class MyController {

    @RequestMapping({"/", "/index"})
    public String toIndex(Model model){
        model.addAttribute("msg","hello shiro");
        return "index";
    }
}

5.测试

6.创建ShiroConfig和UserRealm

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean:第三步
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        return bean;
    }

    //DefaultWebSecurityManager:第二步
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联UserRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建Realm对象,需要自定义类:第一步
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }
}

ShiroConfig

public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权 doGetAuthorizationInfo");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证 doGetAuthenticationInfo");
        return null;
    }
}

UserRealm

这里ShiroConfig需要从下往上写,每一层都要用@Bean注入到spring容器中进行托管

7.编写add和update跳转页面

8.controller层实现跳转

@Controller
public class MyController {

    @RequestMapping({"/", "/index"})
    public String toIndex(Model model){
        model.addAttribute("msg","hello shiro");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add(){
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update(){
        return "user/update";
    }
}

最后是测试,能成功跳转就代表我们的环境已经搭建好了!

2、shiro实现登录拦截

首先要记住这些:

anon:无需认证就可以访问

authc:必须认证了才能访问

user:必须拥有 记住我 功能才可使用

perms: 拥有对某个资源的权限才可访问

role: 拥有某个角色权限才可访问

1.添加shiro的内置过滤器

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean:第三步
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的内置过滤器
        /*
            anon:无需认证就可以访问
            authc:必须认证了才能访问
            user:必须拥有 记住我 功能才可使用
            perms: 拥有对某个资源的权限才可访问
            role: 拥有某个角色权限才可访问
        */
        //由于是链式的,一般用LinkedHashMap
        Map<String, String> filterMap = new LinkedHashMap<>();

//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");
        filterMap.put("/user/*","authc");

        bean.setFilterChainDefinitionMap(filterMap);

        return bean;
    }
}

2.编写登录表单及按钮

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>登录</h1>
<hr>
<form th:action="@{/login}">
  <p>用户名:<input type="text" name="username"></p>
  <p>密码:  <input type="text" name="password"></p>
  <p><input type="submit"></p>
</form>

</body>
</html>

3.controller层添加跳转请求

4.设置登录的请求

3、Shiro实现用户认证

1.获取用户的数据并且封装,捕获用户名或密码的异常并实现拦截

    @RequestMapping("/login")
    public String login(String username,String password,Model model){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try{
            subject.login(token);//执行登陆方法,如果没有异常就说明OK了
            return "index";
        }catch (UnknownAccountException e){//用户名不存在
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){//密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }

    }

在Controller文件中编写

2.登录页面添加错误提示

<h1>登录</h1>
<hr>
<p th:text="${msg}" style="color:red ;"></p>
<form th:action="@{/login}">
  <p>用户名:<input type="text" name="username"></p>
  <p>密码:  <input type="text" name="password"></p>
  <p><input type="submit"></p>
</form>

3.在UserRealm中进行认证,这里是伪造数据库

public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权 doGetAuthorizationInfo");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证 doGetAuthenticationInfo");

        //用户名,密码  数据库中取
        String name = "root";
        String password = "123456";

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        //用户认证
        if (!name.equals(token.getUsername())){
            return null;//抛出异常  UnknownAccountException
        }

        //密码认证 shiro已经帮我们做了
        return new SimpleAuthenticationInfo("",password,"");
    }
}

4.最后进行测试

4、Shiro整合Mybatis

1.导入依赖

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

2.配置jdbc和druid数据源

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    #SpringBoot默认是不注入这些的,需要自己绑定
    #druid数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Properity
    #则导入log4j 依赖就行
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

3.配置mybatis的properties文件

mybatis.type-aliases-package=com.lqh.pojo
mybatis.mapper-locations=classpath:mapper/*.xml

4.编写实体类

5.编写mapper接口

6.配置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.lqh.mapper.UserMapper">

    <select id="queryUserByName" parameterType="String" resultType="User">
        select *
        from mybatis.user
        where name = #{name};
    </select>

</mapper>

7.编写service层

UserService接口

public interface UserService {
    public User queryUserByName(String name);
}

UserServiceImpl

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    public User queryUserByName(String name) {
        return userMapper.queryUserByName(name);
    }
}

8.测试

@SpringBootTest
class ShiroSpringbootApplicationTests {

    @Autowired
    UserServiceImpl userService;

    @Test
    void contextLoads() {
        System.out.println(userService.queryUserByName("张三"));
    }

}

基本环境就搭好了,接下来去修改认证信息

public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权 doGetAuthorizationInfo");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证 doGetAuthenticationInfo");

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        User user = userService.queryUserByName(token.getUsername());

        if (user==null){//如果没有这个人
            return null;
        }

        //密码认证 shiro已经帮我们做了
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }
}

就可以从数据库中读取用户名和密码了

5、Shiro请求授权实现

1.设置授权

添加了以后就会被拦截进去add页面

2.自己再写一个页面,被拦截以后跳转过去

    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized(){
        return "未经授权无法访问此页面";
    }

未授权时就会跳转

当然也要在UserRealm中添加授权实现拦截

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权 doGetAuthorizationInfo");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //添加一个权限 所有角色拥有user:add才可以通过,不然会被拦截
        info.addStringPermission("user:add");
        //注意返回值不要写错
        return info;
    }

然后进行测试。但是发现在测试的过程中,登录其他的用户也可以进入,所以要做进一步的授权功能。

3.数据库中添加字段perms,手动给两个用户添加权限,修改实体类

用户在认证里查的信息,怎么在授权里做呢?

首先我们需要拿到User的对象

这里的user,上面授权就可以拿到

然后拿到登录对象,设置权限

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权 doGetAuthorizationInfo");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //添加一个权限 所有角色拥有user:add才可以通过,不然会被拦截
        info.addStringPermission("user:add");

        //拿到当前登录的对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();//拿到登录对象

        //设置当前用户的权限
        info.addStringPermission(currentUser.getPerms());

        return info;
    }

测试

root因为在数据库中有这是update权限,可以正常登录进入update页面,但是aaaa并没有设置,所以无法进入,提醒未授权

这里设置的,需要注释掉

6、Shiro整合thymeleaf

1.导入thymeleaf和shiro的整合包

        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.1.0</version>
        </dependency>

2.在ShiroConfig中用ShiroDialect整合shiro和thymeleaf

    //整合ShiroDialect:用来整合shiro thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

3.去首页编写Permission权限

先导入命名空间

<html lang="en" xmlns:th="http://www.thymeleaf.org" 
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">

添加权限,最后再添加一个登录按钮

<h1>首页</h1>
<p>
    <a th:href="@{/toLogin}">登录</a>
</p>
<p th:text="${msg}"></p>

<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
</div>

<div shiro:hasPermission="user:update">
  <a th:href="@{/user/update}">update</a>
</div>

测试

root只有一个权限,所以只会显示update

aaaa一个权限都没有,所以什么都不显示

如果想进入首页去掉登录按钮,添加shiro:notAuthenticated这个标签就可以了

<h1>首页</h1>
<div shiro:notAuthenticated>
    <a th:href="@{/toLogin}">登录</a>
</div>

登录按钮就被干掉了!

8、Swagger

1.SpringBoot集成Swagger

1、新建一个springboot-web项目

2、导入相关依赖

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>3.0.0</version>
        </dependency>

3、编写HelloController,测试确保运行成功

4、要使用Swagger,我们需要编写一个配置类-SwaggerConfig来配置 Swagger

@Configuration //配置类
@EnableSwagger2// 开启Swagger2的自动配置
public class SwaggerConfig {  
}

5、访问测试 :http://localhost:8080/swagger-ui.html ,可以看到swagger的界面

2.配置Swagger

1、Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger。

@Bean //配置docket以配置Swagger具体参数
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2);
}

2、可以通过apiInfo()属性配置文档信息

//配置文档信息
private ApiInfo apiInfo() {
   Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
   return new ApiInfo(
           "Swagger学习", // 标题
           "学习演示如何配置Swagger", // 描述
           "v1.0", // 版本
           "http://terms.service.url/组织链接", // 组织链接
           contact, // 联系人信息
           "Apach 2.0 许可", // 许可
           "许可链接", // 许可连接
           new ArrayList<>()// 扩展
  );
}

3、Docket 实例关联上 apiInfo()

@Bean
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}

4、重启项目,访问测试 http://localhost:8080/swagger-ui.html 看下效果;

3.配置扫描接口

1、构建Docket时通过select()方法配置怎么扫描接口。

2、重启项目测试,由于我们配置根据包的路径扫描接口,所以我们只能看到一个类

3、除了通过包路径配置扫描接口外,还可以通过配置其他方式扫描接口,这里注释一下所有的配置方式:

    //配置了Swagger的Docket的bean实例
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)
                        .apiInfo(apiInfo())
                        .select()
                        //通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
                        //basePackage:指定要扫描的包
                        //RequestHandlerSelectors.any() :扫描全部
                        //RequestHandlerSelectors.none():都不扫描
                        //RequestHandlerSelectors.withClassAnnotation():扫描类上的注解,参数是一个注解的反射对象
                        //RequestHandlerSelectors.withMethodAnnotation():扫描方法上的注解
                        .apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
                        .build();
    }

4、除此之外,我们还可以配置接口扫描过滤:

    //配置了Swagger的Docket的bean实例
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)
                        .apiInfo(apiInfo())
                        .select()
                        .apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
                        //paths() 过滤什么路径
                        .paths(PathSelectors.ant("example/**"))
                        .build();
    }

5、这里的可选值还有

any() // 任何请求都扫描
none() // 任何请求都不扫描
regex(final String pathRegex) // 通过正则表达式控制
ant(final String antPattern) // 通过ant()控制

4、配置Swagger开关

1、通过enable()方法配置是否启用swagger,如果是false,swagger将不能在浏览器中访问了

    //配置了Swagger的Docket的bean实例
    @Bean
    public Docket docket(Environment environment){
        return new Docket(DocumentationType.SWAGGER_2)
                        .apiInfo(apiInfo())
                        .enable(flag)//enable是否启动Swagger,如果为false,则Swagger不能在浏览器中访问
                        .select()
                        .apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
                        //paths() 过滤什么路径
                        //.paths(PathSelectors.ant("example/**"))
                        .build();
    }

2、如何动态配置当项目处于test、dev环境时显示swagger,处于prod时不显示?

    //配置了Swagger的Docket的bean实例
    @Bean
    public Docket docket(Environment environment){

        //设置要显示的Swagger环境
        Profiles profiles = Profiles.of("dev");
        //通过environment.acceptsProfiles()判断是否处在自己设定的环境当中
        //通过 enable() 接收此参数判断是否要显示
        boolean flag = environment.acceptsProfiles(profiles);


        return new Docket(DocumentationType.SWAGGER_2)
                        .apiInfo(apiInfo())
                        .enable(flag)//enable是否启动Swagger,如果为false,则Swagger不能在浏览器中访问
                        .select()
                        .apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
                        //paths() 过滤什么路径
                        //.paths(PathSelectors.ant("example/**"))
                        .build();
    }

3、可以在项目中增加一个dev的配置文件查看效果

选择环境

5、配置API分组

1、如果没有配置分组,默认是default。通过groupName()方法即可配置分组:

    //配置了Swagger的Docket的bean实例
    @Bean
    public Docket docket(Environment environment){

        //设置要显示的Swagger环境
        Profiles profiles = Profiles.of("dev");
        //通过environment.acceptsProfiles()判断是否处在自己设定的环境当中
        boolean flag = environment.acceptsProfiles(profiles);


        return new Docket(DocumentationType.SWAGGER_2)
                        .apiInfo(apiInfo())
                        .groupName("lqh")
                        .enable(flag)//enable是否启动Swagger,如果为false,则Swagger不能在浏览器中访问
                        .select()
                        .apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
                        //paths() 过滤什么路径
                        //.paths(PathSelectors.ant("example/**"))
                        .build();
    }

2、重启项目查看分组

3、如何配置多个分组?配置多个分组只需要配置多个docket即可:

    @Bean
    public Docket docket1(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("A");
    }

    @Bean
    public Docket docket2(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("B");
    }

    @Bean
    public Docket docket3(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("C");
    }

4、重启项目查看即可

6、实体配置

1、新建一个实体类

@ApiModel("用户实体类")
public class User {

    @ApiModelProperty("用户名")
    public String username;
    @ApiModelProperty("密码")
    public String password;

}

2、只要这个实体在请求接口的返回值上(即使是泛型),都能映射到实体项中:

    //只要我们的接口中,返回值存在实体类,它就会被扫描到Swagger中
    @PostMapping(value = "/user")
    public User user(){
        return new User();
    }

3、重启查看测试

注:并不是因为@ApiModel这个注解让实体显示在这里了,而是只要出现在接口方法的返回值上的实体都会显示在这里,而@ApiModel和@ApiModelProperty这两个注解只是为实体添加注释的。

@ApiModel为类添加注释

@ApiModelProperty为类属性添加注释

7、常用注解

Swagger的所有注解定义在io.swagger.annotations包下

下面列一些经常用到的,未列举出来的可以另行查阅说明:

@Api(tags = “xxx模块说明”):作用在模块类上

@ApiOperation(“xxx接口说明”):作用在接口方法上

@ApiModel(“xxxPOJO说明”):作用在模型类上:如VO、BO@ApiModelProperty(value = “xxx属性说明”,hidden = true)作用在类方法和属性上,hidden设置为true可以隐藏该属性@ApiParam(“xxx参数说明”):作用在参数、方法和字段上,类似@ApiModelProperty

我们也可以给请求的接口配置一些注释

    //Operation接口,不是放在类上的,是方法
    @ApiOperation("Hello控制类")
    @GetMapping(value = "/hello2")
    @ResponseBody
    public String hello2(@ApiParam("用户名") String username){
        return "hello"+username;
    }

这样的话,可以给一些比较难理解的属性或者接口,增加一些配置信息,让人更容易阅读!

相较于传统的Postman或Curl方式测试接口,使用swagger简直就是傻瓜式操作,不需要额外说明文档(写得好本身就是文档)而且更不容易出错,只需要录入数据然后点击Execute,如果再配合自动化框架,可以说基本就不需要人为操作了。

Swagger是个优秀的工具,现在国内已经有很多的中小型互联网公司都在使用它,相较于传统的要先出Word接口文档再测试的方式,显然这样也更符合现在的快速迭代开发行情。当然了,提醒下大家在正式环境要记得关闭Swagger,一来出于安全考虑二来也可以节省运行时内存。

9、异步、定时、邮件任务

1.异步任务

1、创建一个service包

2、创建一个类AsyncService

异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。

编写方法,假装正在处理数据,使用线程设置一些延时,模拟同步等待的情况;

@Service
public class AsyncService {

   public void hello(){
       try {
           Thread.sleep(3000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       System.out.println("数据正在处理....");
  }
}

3、编写controller包

4、编写AsyncController类

我们去写一个Controller测试一下

@RestController
public class AsynController {

    @Autowired
    AsynService asynService;

    @RequestMapping("/hello")
    public String hello(){
        asynService.hello();
        return "OK";
    }


}

5、访问http://localhost:8080/hello进行测试,3秒后出现OK,这是同步等待的情况。

问题:我们如果想让用户直接得到消息,就在后台使用多线程的方式进行处理即可,但是每次都需要自己手动去编写多线程的实现的话,太麻烦了,我们只需要用一个简单的办法,在我们的方法上加一个简单的注解即可,如下:

6、给hello方法添加@Async注解;

    //告诉Spring这是一个异步方法
    @Async
    public void hello(){

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据正在处理......");
    }

SpringBoot就会自己开一个线程池,进行调用!但是要让这个注解生效,我们还需要在主程序上添加一个注解@EnableAsync ,开启异步注解功能;

@EnableAsync  //开启异步注解功能
@SpringBootApplication
public class Springboot09TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot09TestApplication.class, args);
    }

}

7、重启测试,网页瞬间响应,后台代码依旧执行!

2.定时任务

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。

  • TaskExecutor接口

  • TaskScheduler接口

两个注解:

  • @EnableScheduling

  • @Scheduled

测试步骤:

1、创建一个ScheduledService

我们里面存在一个hello方法,他需要定时执行,怎么处理呢?

@Service
public class ScheduleService {
    //在一个特定的时间执行这个方法
    //cron表达式
    //秒 分 时 日 月 周几
    @Scheduled(cron =  "0 * * * * 0-7")
    public void hello(){
        System.out.println("hello,你被执行了");
    }

}

2、这里写完定时任务之后,我们需要在主程序上增加@EnableScheduling 开启定时任务功能

@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class SpringbootTaskApplication {

   public static void main(String[] args) {
       SpringApplication.run(SpringbootTaskApplication.class, args);
  }

}

3、我们来详细了解下cron表达式;

http://www.bejson.com/othertools/cron/

4、常用的表达式

(1)0/2 * * * * ?   表示每2秒 执行任务
(1)0 0/2 * * * ?   表示每2分钟 执行任务
(1)0 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED   表示每个星期三中午12点
(7)0 0 12 * * ?   每天中午12点触发
(8)0 15 10 ? * *   每天上午10:15触发
(9)0 15 10 * * ?     每天上午10:15触发
(10)0 15 10 * * ?   每天上午10:15触发
(11)0 15 10 * * ? 2005   2005年的每天上午10:15触发
(12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED   每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI   周一至周五的上午10:15触发
(18)0 15 10 15 * ?   每月15日上午10:15触发
(19)0 15 10 L * ?   每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发

3.邮件任务

邮件发送,在我们的日常开发中,也非常的多,Springboot也帮我们做了支持

  • 邮件发送需要引入spring-boot-start-mail

  • SpringBoot 自动配置MailSenderAutoConfiguration

  • 定义MailProperties内容,配置在application.yml中

  • 自动装配JavaMailSender

  • 测试邮件发送

1、引入pom依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

2、修改配置文件

spring:
  mail:
    username: 835788261@qq.com
    password: 你的qq授权码
    host: smtp.qq.com
    properties: {mail.smtl.ssl.enable: true}

3、Spring单元测试

 @Autowired
    JavaMailSenderImpl mailSender;


    @Test
    void contextLoads() {
        SimpleMailMessage message = new SimpleMailMessage();

        message.setSubject("你好呀");
        message.setText("你是猪");

        message.setTo("835788261@qq.com");
        message.setFrom("835788261@qq.com");

        mailSender.send(message);
    }

    @Test
    void contextLoads1() throws MessagingException {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);

        helper.setSubject("你好呀plus");
        helper.setText("<p style='color:red'>你是猪</p>",true);

        helper.addAttachment("1.jpg",new File("C:\Users\1\Desktop\1.jpg"));
        helper.addAttachment("2.jpg",new File("C:\Users\1\Desktop\1.jpg"));

        helper.setTo("835788261@qq.com");
        helper.setFrom("835788261@qq.com");

        mailSender.send(mimeMessage);
    }

最后成功接收到消息和附件。

10、Dubbo&Zookeeper

1.Dubbo

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

dubbo官网 http://dubbo.apache.org/zh-cn/index.html

1.了解Dubbo的特性

2.查看官方文档

服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。

服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者

监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

调用关系说明

l 服务容器负责启动,加载,运行服务提供者。

l 服务提供者在启动时,向注册中心注册自己提供的服务。

l 服务消费者在启动时,向注册中心订阅自己所需的服务。

l 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

l 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

l 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

2.Dubbo+Zookeeper环境搭建

Zookeeper

1、下载zookeeper

2、运行/bin/zkServer.cmd ,初次运行会报错,没有zoo.cfg配置文件;

可能遇到问题:闪退 !

解决方案:编辑zkServer.cmd文件末尾添加pause 。这样运行出错就不会退出,会提示错误信息,方便找到原因。

3、修改zoo.cfg配置文件

将conf文件夹下面的zoo_sample.cfg复制一份改名为zoo.cfg即可。

注意几个重要位置:

dataDir=./ 临时数据存储的目录(可写相对路径)

clientPort=2181 zookeeper的端口号

修改完成后再次启动zookeeper

Dubbo

dubbo本身并不是一个服务软件。它其实就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。

但是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序dubbo-admin,不过这个监控即使不装也不影响使用。

我们这里来安装一下:

1、下载dubbo-admin

地址 :GitHub - apache/dubbo-admin at master-0.2.0

2、解压进入目录

修改 dubbo-adminsrcmain esources application.properties 指定zookeeper地址

server.port=7001
spring.velocity.cache=false
spring.velocity.charset=UTF-8
spring.velocity.layout-url=/templates/default.vm
spring.messages.fallback-to-system-locale=false
spring.messages.basename=i18n/message
spring.root.password=root
spring.guest.password=guest

dubbo.registry.address=zookeeper://127.0.0.1:2181

3、在项目目录下打包dubbo-admin

mvn clean package -Dmaven.test.skip=true

4、执行 dubbo-admin arget 下的dubbo-admin-0.0.1-SNAPSHOT.jar

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

【注意:zookeeper的服务一定要打开!】

执行完毕,我们去访问一下 http://localhost:7001/ , 这时候我们需要输入登录账户和密码,我们都是默认的root-root;

登录成功后,查看界面

3.SpringBoot+Dubbo+Zookeeper

1. 启动zookeeper !

2. IDEA创建一个空项目;

3.创建一个模块,实现服务提供者:provider-server , 选择web依赖即可

4.项目创建完毕,我们写一个服务,比如卖票的服务;

package com.lqh.service;

public interface TicketService {
    public String getTicket();
}

编写实现类

public class TicketServiceImpl implements TicketService{
    @Override
    public String getTicket() {
        return "123";
    }
}

5.创建一个模块,实现服务消费者:consumer-server , 选择web依赖即可

6.项目创建完毕,我们写一个服务,比如用户的服务;

编写service

public class UserService {

    //想拿到provider-server提供的票,要去注册中心拿到服务

}

服务提供者

1、将服务提供者注册到注册中心,我们需要整合Dubbo和zookeeper,所以需要导包。我们从dubbo官网进入github,看下方的帮助文档,找到dubbo-springboot,找到依赖包。这里将所需的全部导入

 <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.8</version>
        </dependency>

        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>

        <!-- 引入zookeeper -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <!--排除这个slf4j-log4j12-->
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2、在springboot配置文件中配置dubbo相关属性

#端口号
server.port=8001
#服务应用名字
dubbo.application.name=provider-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#哪些服务要被注册
dubbo.scan.base-packages=com.lqh.service

3、在service的实现类中配置服务注解,发布服务。注意导包问题

import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Component;

@DubboService //将服务发布出去
@Component //这里用@Component注入到容器中,也可以用@Service,但是需要注意导包
public class TicketServiceImpl implements TicketService{
    @Override
    public String getTicket() {
        return "123";
    }
}

为了区分Dubbo的Service和Spring的Service,这里已经将注解改为了@DubboService

服务消费者

1、导入依赖,和之前的依赖一样

 <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.8</version>
        </dependency>

        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>

        <!-- 引入zookeeper -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <!--排除这个slf4j-log4j12-->
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2、配置参数

#端口号
server.port=8002
#消费者去哪里拿服务,需要暴露自己的名字
dubbo.application.name=consumer-server
#注册中心的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

3. 本来正常步骤是需要将服务提供者的接口打包,然后用pom文件导入,我们这里使用简单的方式,直接将服务的接口拿过来,路径必须保证正确,即和服务提供者相同;

4. 完善消费者的服务类

package com.lqh.service;


import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    //想拿到provider-server提供的票,要去注册中心拿到服务
    @DubboReference //远程引用指定的服务,他会按照全类名进行匹配,看谁给注册中心注册了这个全类名    
    TicketService ticketService;

    public void buyTicket(){
        String ticket = ticketService.getTicket();
        System.out.println("在注册中心拿到了=>"+ticket);
    }
}

5. 编写测试类

@SpringBootTest
class ConsumerServerApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void contextLoads() {
        userService.buyTicket();
    }

}

启动测试

1. 开启zookeeper

2. 打开dubbo-admin实现监控【可以不用做】

3. 开启服务者

4. 消费者消费测试,结果:

监控中心 :

文章部分转载自:终于,狂神说SSM及SpringBoot系列文章完更!!!_狂神说-CSDN博客_狂神说springboot

个人学习及复习使用,仅供参考

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值