美文网首页
高级实训

高级实训

作者: Scincyc | 来源:发表于2020-07-26 12:41 被阅读0次

    微服务简介

    分布式简介

    springboot使用

    springboot是一个框架大集合,包含我们常见的大部分框架,spring官方已经替我们集成好了,我们不需要写任何的配置文件,直接dependency依赖即可。spring官方提供了一套快速建立应用的机制就是springboot

    创建/运行/打包

    maven辅助工具:创建工程,配置工程(jar包,tomcat),运行工程,打包工程

    maven中国镜像:

        <mirror>
            <id>nexus-aliyun</id>
            <mirrorOf>central</mirrorOf>
            <name>Nexus aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
          </mirror>
    

    maven中央仓库:

    https://mvnrepository.com/

    maven tomcat插件:

    <!--插件 tomcat-->
        <plugins>
    
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
    
            <configuration>
              <path>/</path> <!-- 项目访问路径 本例:localhost:9090, 如果配置的aa,则访问路径为localhost:9090/aa -->
              <port>8086</port>
              <uriEncoding>UTF-8</uriEncoding><!-- 非必需项 -->
            </configuration>
          </plugin>
    
        </plugins>
    

    打包:

    jar/war

    jar:第三方的人写好的工程,编译成 jar包,我们得到jar包,可以在工程中直接调用其中的类库

    war:web包,可以放到tomcat的webapps文件夹中,直接运行。xxxxxx.war

    springboot官方推荐打成jar包方式,当然也支持war包。

    springboot启动jar的方式为:

    快捷提示的tab键

    java -jar demo5-0.0.1-SNAPSHOT.jar
    

    springboot配置文件

    配置文件中可以 配置springboot的各个框架的配置信息

    例如:tomcat端口,访问路径,数据库用户名/密码,等等

    idea有自动提示,不要记忆

    详细的配置请见官方文档:

    附录A

    YML语法

    springboot的配置文件支持两种格式;

    一种是:xxx.properties

    另一种是:xxx.yml

    server:
      port: 8087
      servlet:
        context-path: /hhh
    

    注意:

    yml的语法是k: v v前面必须有一个空格,否则无效。

    配置文件注入

    使用@ConfigurationProperties(prefix = "person")从我们的配置文件中读取用户配置数据,该注解支持yml和properties

    @Component注解和导入配置文件无关,作用是把我们的person类放入到spring的容器 中(注册成bean)

    @Component
    @ConfigurationProperties(prefix = "person")
    public class Person {
    
        private int age;
        private String  name;
        private boolean sex;
        List<String > list;
        Map<String,Object> map;
        Cat cat;
        //.......getter setter  tostring
    }
    
    public class Cat {
        private int age;
        private String name;
        //......
    }
    
    @Controller
    public class HelloController {
    
        //从容器中取出person的值
        @Autowired
        Person person;
    
    //    springboot的 方法比直接maven工程更加快速
        @ResponseBody
        @RequestMapping("hello")
        //hello和/hello效果一样
        public String hello(){
            System.out.println(person);
            return "hello everyone";
        }
    }
    
    server:
      port: 8087
      servlet:
        context-path: /hhh
    
    #作用;给用户留出配置的接口,用户配置成什么,那么我们的程序运行的时候就是什么值
    person:
      age: 30
      name: zhangsan
      sex: true
      list:
        - aaaa
        - bbbb
        - cccc
      map:
        f: fffff
        g: ggggg
      cat:
        age: 2
        name: ahuang
    
    person.age=40
    person.name=lisi
    person.sex=true
    person.list=qqq,www,eee
    person.map.k1=kkkkk
    person.map.k2=ttttt
    person.cat.age=1
    person.cat.name=ahei
    

    第二种注入值的方式:

    @Value

        @Value("${mysql.mypwd}")
        String pwd;
    
    @ConfigurationProperties @Value
    支持多数据导入 单一数据导入
    支持参数校验 不支持参数校验

    参数校验

    springmvc参数校验

    @ConfigurationProperties(prefix = "person")支持参数校验

    参数校验:验证参数的类型是否合规。

    注解 说明 备注
    AssertTrue 标注元素必须为true boolean,Boolean,Null
    AssertFalse 标注元素必须为false boolean,Boolean,Null
    DecimalMax(value,isclusive) 标注元素必须小于等于指定值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    DecimalMin(value,isclusive) 标注元素必须大于等于指定值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    Digits(integer,fraction) 标注元素必须位于指定位数之内 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    Email(regexp,flags) 标注元素必须为格式正确的邮件地址 CharSequence
    Future 标注元素必须为将来的日期 Date,Calendar,Instant, LocalDate,LocalDateTime, LocalTime,MonthDay, OffsetDateTime,OffsetTime, Year,YearMonth, ZonedDateTime,HijrahDate, JapaneseDate,MinguoDate, ThaiBuddhistDate
    FutureOrPresent 标注元素必须为现在或将来的日期 同Future
    Max(value) 标注元素必须小于等于指定值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    Min(value) 标注元素必须大于等于指定值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    Negative 标注元素必须为严格负值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    NegativeOrZero 标注元素必须为严格的负值或者0值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    NotBlank 标注元素必须不为null,且必须包含至少一个非空字符 CharSequence
    NotEmpty 标注元素必须不为null,且必须包含至少一个子元素 CharSequence,Collection,Map,Array
    NotNull 标注元素必须不为null all
    Null 标注元素必须为null all
    Past 标注元素必须为过去的日期 同Future
    PastOrPresent 标注元素必须为过去的或者现在的日期 同Future
    Pattern(regexp,flags) 标注元素必须匹配给定的正则表达式 CharSequence,Null
    Positive 标注元素必须为严格的正值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    PositiveOrZero 标注元素必须为严格的正值或者0值 BigDecimal,BigInteger, CharSequence,byte,short, int, long,Byte,Short, Integer,Long,Null
    Size(min,max) 标注元素必须在指定范围之内 CharSequence,Collection,Map,Array

    上面的罗列的注解均可作用于方法、字段、构造器、参数,还有注解类型之上,其中作用为注解类型目的就是为了组合多个校验,从而自定义一个组合校验注解。

    Hibernate Validation

    Hibernate Validation承载自JSR 303的Bean Validation,拥有其所有功能,并对其进行了扩展,它自定义了以下校验注解:

    注解 说明 备注
    Length(min,max) 标注元素的长度必须在指定范围之内,包含最大值 字符串
    Range(min,max) 标注元素值必须在指定范围之内 数字值,或者其字符串形式
    URL(regexp,flags) 标注元素必须为格式正确的URL 字符串
    URL(protocol,host,port) 标注元素必须满足给定的协议主机和端口号 字符串
    
    

    课下自己可以把这些校验尝试一下。

    参数校验实现:

    @Component
    @ConfigurationProperties(prefix = "person")
    @Validated
    public class Person {
        @Size(min = 5,max = 20)
        private int age;
        @Email
        private String  name;
        @NotNull
        private boolean sex;
        List<String > list;
        Map<String,Object> map;
        Cat cat;
        //..........
    }
    

    @Validated注解是说,该类需要参数校验。

    具体的校验规则见上文。

    第二种情况:我们在springmvc中也经常用到校验

    如下:

    @RestController
    public class VaildateController {
    
    //    @ResponseBody
        @RequestMapping("test")
        public  String test(@Validated Cat cat, BindingResult result){
            String s = null;
            List<ObjectError> allErrors = result.getAllErrors();
            for (ObjectError e : allErrors) {
                System.out.println(e.getDefaultMessage());
                s=e.getDefaultMessage();
            }
            return s;
        }
    }
    
    public class Cat {
        @Min(1)
        @Max(3)
        private int age;
        @Email
        private String name;
        //.......
    }
    

    加载指定配置文件

    @PropertySource该注解可以用来加载用户指定的配置文件,但是注意,该注解不支持yml文件的自定义加载。所以,如果我们的工程中需要有一些自己的配置文件,那么后缀请使用properties。

    @PropertySource(value = {"classpath:myconfig.properties"})
    

    springboot配置文件的推荐写法

    我们在以前的学习过程中,如果使用一个框架,例如mybatis /shiro,我们会讲该框架以xml的方式配置进来。

    现在springboot官方推荐使用java类+注解的方式来实现各个框架的配置。

    情况一:很多框架springboot官方是默认集成的,详情看spring-boot-starter-xxxxx,那么直接导入denpedency即可,不需要配置。直接用即可。

    情况二:有一些框架springboot官方未做集成,例如shiro,我们需要自己写配置。使用@Configration+@Bean来完成。详情见shiro。

    配置文件多文档块

    在yml文件中:

    server:
      port: 8087
      servlet:
        context-path: /hhh
    spring:
      profiles:
        active: dev
    #    我们在开发时经常使用这种方式配置多环境
    ---
    
    
    server:
      port: 8088
    spring:
      profiles: test
    
    
    ---
    
    
    
    server:
      port: 8089
    spring:
      profiles: dev
    
    
    ---
    server:
      port: 8099
    spring:
      profiles: deploy
    
    在properties文件中使用如下方式做多文档块。
    server.port=8090
    spring.profiles.active=test
    

    application.properties;

    server.port=9092
    

    application-test.properties;

    server.port=9095
    

    application-dev.properties;

    随机数

    my.secret=${random.value}
    my.number=${random.int}
    my.bignumber=${random.long}
    my.uuid=${random.uuid}
    my.number.less.than.ten=${random.int(10)}
    my.number.in.range=${random.int[1024,65536]}
    

    作为了解。

    配置文件加载位置

    SpringBoot从以下位置的 application.properties 文件加载属性,并将它们添加到Spring Environment :

    \1. 当前目录

    \2. 当前目录的 /config 子目录

    \3. 类路径根

    \4. 类路径根 /config 包

    优先级依次由低到高

    springboot日志集成

    原理剖析

    springboot官方使用的是slf4j来实现日志功能。

    springboot是如何统一各个框架的日志的:

    首先它会排除其他框架中 自带的日志框架(开发时需要我们注意,我们需要手动去删除其他的日志包,否则会冲突报错)

    例如:

            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-redis</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>jcl-over-slf4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    

    然后将自己的替换包导入(就在logging中)为了防止其他框架因为第一步删除日志包而报错

    最后统一使用slf4j做日志输出管理

    springboot log日志输出优先级:

    error

    warn

    info

    debug

    trace

    #配置日志输出级别,默认级别是info
    logging.level.com.example.baidu=trace
    

    如何配置日志的位置和日志名称

    #path:日志的路径
    logging.file.path=d://log/xxx/aaa
    #name:日志问价名称
    #logging.file.name=mylog
    注意:path和name两个配置,不可以同时使用,如果同时出现,那么path不生效
    

    控制台日志格式:

    logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n 
    logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n
    

    解释

    %d{HH:mm:ss.SSS}——日志输出时间
    
    %thread——输出日志的进程名字,这在Web应用以及异步任务处理中很有用
    
    %-5level——日志级别,并且使用5个字符靠左对齐
    
    %logger- ——日志输出者的名字
    
    %msg——日志消息
    
    %n——平台的换行符
    

    日志实现

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </dependency>
    
            Logger logger = LoggerFactory.getLogger(getClass());
            logger.error("error");
            logger.info("info");
            logger.warn("warn");
            logger.debug("debug");
            logger.trace("trace");
    

    springboot web集成

    json

    //    springboot中默认使用jackson做json
    //    @ResponseBody 将结果以字符串的形式输出,但是如果结果是其他数据类型,该注解会自动将其转换成json字符串
    //    @RequestBody Person p  该注解会将前端传递过来的json字符串,自动解析成对象
    //    我们开发时经常搞前后端分离,数据交互一率统一使用json,包括android/ios
    

    静态资源

    springboot官方指定的静态资源路径:

    /static

    /public

    /resources

    /META-INF/resources

    我们可以将css/js/image/video/mp3等资源放入到该文件夹下,系统会自动读取

    另一种静态资源导入方式是:webjars

    它是以maven的方式导入静态资源

    默认路径是/META-INF/resources这个静态资源文件夹

    模板引擎thymeleaf

    如果要访问template模板中html网页,那么必须引入thymeleaf模板,否则404

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

    注意:template模板中的html不可以通过浏览器直接访问。只能通过springboot(springmvc)转发(return)

    欢迎页:

    index.html页面是系统默认的欢迎页 ,可以放到static静态资源下,也可以放到template下。、

    网站图标:

    将图片放到static静态文件夹下即可,名称为favicon.ico。

    需要注意的是:如果你的工程添加了server.servlet.context-path,那么可能会找不到图片,因为路径不对。

    错误页面:

    在template文件夹下新建error路径,在其中写入4xx.html和5xx.html网页,当发生404 503等错误的时候,会自动返回该页面。

    restful风格

    restfull是一种风格

    支持put改 delete删 get查 post增

    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <script src="webjars/jquery/3.5.1/jquery.js"></script>
    </head>
    <body>
    <button id="delete">删除文章</button>
    <button id="add">添加文章</button>
    <button id="update">修改文章</button>
    <button id="query">查询文章</button>
    
    <script>
        $("#delete").click(function () {
            $.ajax({
                url:"456/artical/76598",
                type: "delete",
                dataType:"json",
                success:function (data) {
                    console.log(data)
                }
            });
        });
    
        $("#update").click(function () {
            $.ajax({
                url:"123/artical/76598000",
                type: "put",
                dataType:"json",
                success:function (data) {
                    console.log(data)
                }
            });
        });
    </script>
    </body>
    </html>
    
    @RestController
    public class RestfulController {
    
        @DeleteMapping("/{uid}/artical/{aid}")
        public String deleteArtical(@PathVariable String aid,@PathVariable String uid){
            System.out.println(aid);
            System.out.println(uid);
            return "删除成功";
        }
    
    
        @PutMapping("/{uid}/artical/{aid}")
        public String putArtical(@PathVariable String aid,@PathVariable String uid){
            System.out.println(aid);
            System.out.println(uid);
            return "删除成功";
        }
        
        
        //    @GetMapping
        //    @PostMapping
    }
    
    

    数据库

    jooq

    遗留

    逆向生成

    生成过程:略

    使用:

        @Autowired
        CityMapper cityMapper;
    
        @GetMapping("/allcity")
        public List getAllCity(){
            CityExample example = new CityExample();
            example.createCriteria().andPopulationBetween(10000,100000);
            List<City> cities = cityMapper.selectByExample(example);
            return cities;
        }
    

    错误修改:

    1/ 数据库 配置

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

    2/ IDEA-解决: org.apache.ibatis.binding.BindingException:Invalid bound statement (not found)

    无法找到mapper.xml文件

    因为我们把mapper.xml文件放入到java文件下,默认springboot是不扫描java文件夹下 的xml文件的。

    但是我们要让它扫描:

    在pom.xml文件中加入:

            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*</include>
                    </includes>
                </resource>
            </resources>
    

    3/在启动类上,加入mybatis接口的扫描注解,用来扫描mybatis的接口,放入到spring的容器中。

    @MapperScan("com.example.tedu.dao")

    @MapperScan("com.example.tedu.dao")
    @SpringBootApplication
    public class Demo6Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Demo6Application.class, args);
        }
    
    }
    

    分页插件

    1/导包

            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>LATEST</version>
            </dependency>
    

    2/java

    PageHelper.startPage(3,20);

        @GetMapping("/allcity")
        public List getAllCity(){
            CityExample example = new CityExample();
            example.createCriteria().andPopulationBetween(10000,100000);
            PageHelper.startPage(3,20);
            List<City> cities = cityMapper.selectByExample(example);
            return cities;
        }
    

    shiro使用

    https://www.cnblogs.com/feiyu127/p/7700090.html

    概念:

    sbuject:当前用户

    SecurityManager:安全管理者,用户想访问 我们的网站,必须经过它。判断你请求的资源是什么限制类型(anon,authc等),如果是authc认证,那么它会调用realm,去做认证。

    realm:shiro用它连接数据源(配置文件,文件,数据库等),我们经常自定义 realm用它连接数据库。

    Authentication:认证,加密,加盐,迭代等

    Authorization:授权,角色rose,权限permission

    在这里插入图片描述

    springboot集成shiro

    1/导包

            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>LATEST</version>
            </dependency>
    

    2/配置shiro,编写 配置文件(java)

    package com.example.tedu.shiro;
    
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Created by colors on 2020/7/15.
     * xml配置文件方式在5年前就被抛弃了
     */
    @Configuration
    public class ShiroConfig {
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            Map<String,String> map = new HashMap<>();
            map.put("/css/**","anon");
            map.put("/js/**","anon");
            map.put("/images/**","anon");
            map.put("/webjars/**","anon");
            map.put("/login","anon");
            map.put("/loginPage","anon");
            map.put("/register","anon");
            map.put("/registerPage","anon");
            map.put("/page1","anon");
            map.put("/page2","anon");
            map.put("/logout","logout");
            map.put("/**","authc");
    //        过滤链
            shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
    //        认证页面
            shiroFilterFactoryBean.setLoginUrl("/loginPage");
    //        ref
            shiroFilterFactoryBean.setSecurityManager(securityManager());
            return shiroFilterFactoryBean;
        }
    
        @Bean
        public SecurityManager securityManager(){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(customRealm());
            return securityManager;
        }
    
    //    自定义realm
        @Bean
        public CustomRealm customRealm(){
            CustomRealm customRealm = new CustomRealm();
            customRealm.setCredentialsMatcher(credentialsMatcher());
            return customRealm;
        }
    
        @Bean
        public HashedCredentialsMatcher credentialsMatcher(){
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            credentialsMatcher.setHashAlgorithmName("md5");
            credentialsMatcher.setHashIterations(10000);
            credentialsMatcher.setStoredCredentialsHexEncoded(true);
            return credentialsMatcher;
        }
    
    
        //加入注解的使用,不加入这个注解不生效
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
        //    启动shiro
        @Bean
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
            creator.setProxyTargetClass(true);
            return creator;
        }
    //    //shiro网页标签
    //    @Bean
    //    public ShiroDialect shiroDialect() {
    //        return new ShiroDialect();
    //    }
    }
    
    

    3/自定义realm

    package com.example.tedu.shiro;
    
    import com.example.tedu.dao.UserMapper;
    import com.example.tedu.pojo.Permission;
    import com.example.tedu.pojo.Role;
    import com.example.tedu.pojo.User;
    import com.example.tedu.pojo.UserExample;
    import com.example.tedu.serivce.LoginService;
    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.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.realm.AuthenticatingRealm;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.List;
    
    /**
     * Created by colors on 2020/7/15.
     * 操作数据库
     */
    public class CustomRealm  extends AuthorizingRealm {
    
        @Autowired
        LoginService loginService;
    
        @Autowired
        UserMapper userMapper;
    
    //    认证 获取用户信息 还没有做认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            String name = authenticationToken.getPrincipal().toString();
            if (name==null){
                return null;
            }else {
                //拿着用户名查询数据库,得到用户信息
                User user = loginService.login(name);
                if (user==null){
                    return null;
                }else {
    //                hashedCredentials密码
    //                用数据库的数据,做一个认证信息,交给shiro
                    SimpleAuthenticationInfo authenticationInfo =
                            new SimpleAuthenticationInfo(name,user.getPassword().toString(), ByteSource.Util.bytes(user.getSalt()),getName());
                    return authenticationInfo;
                }
    
            }
        }
    
    //    授权
    //    shiro中的权限分为role和 permission两种
    //    做项目时,数据库设计最重要,底层基础决定上层高度
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    
            String name = (String) principalCollection.getPrimaryPrincipal();
            UserExample example = new UserExample();
            example.createCriteria().andUsernameEqualTo(name);
            List<User> users = userMapper.selectByExample(example);
            if (users.size()!=0){
                User user = users.get(0);
                Role role = userMapper.queryRole(user.getId());
    //            将用户角色信息放入到shiro中
                authorizationInfo.addRole(role.getRole());
            }
    
            List<Permission> permissions = userMapper.queryPermission(name);
            if (permissions.size()!=0){
                for (Permission p : permissions) {
                    authorizationInfo.addStringPermission(p.getPermission());
                }
            }
            return authorizationInfo;
    
    //        org.apache.shiro.authz.AuthorizationException
        }
    
    //    public static void main(String[] args) {
    //        SimpleHash simpleHash =
    //                new SimpleHash("md5","123456",
    //                        "v9o]zPD22,IX[IjZAet4cr+\\k]IChe6;fE 'y6qj +9.bGPD^C",100);
    //
    //        System.out.println(simpleHash.toString());
    //    }
    
    }
    
    

    4/登录

    @Controller
    public class LoginController {
    
        @RequestMapping("index")
        public String index(){
            return "index";
        }
    
        @RequestMapping("page1")
        public String page1(){
            return "page1";
        }
    
    
        @RequestMapping("page2")
        public String page2(){
            return "page2";
        }
    
    
        @RequiresRoles("sadmin")
        @RequestMapping("page3")
        public String page3(){
            return "page3";
        }
    
        @RequestMapping("loginPage")
        public String loginPage(){
            return "login";
        }
    
        @RequestMapping("login")
        public String login(User user, Model model, HttpSession session){
    //        subject存放着你的信息(数据库中的)
            Subject subject = SecurityUtils.getSubject();
            //做一个令牌token,存放用户的网页用户名和密码
            UsernamePasswordToken token =
                    new UsernamePasswordToken(user.getUsername(),user.getPassword());
    //        login是shiro替我们做匹配认证
            try {
                subject.login(token);
            }catch (UnknownAccountException e){
                model.addAttribute("msg","用户不存在");
                return "login";
            }catch (IncorrectCredentialsException e){
                model.addAttribute("msg","密码错误");
                return "login";
            }
    
            session.setAttribute("name",user.getUsername());
    
    //        org.apache.shiro.authc.UnknownAccountException用户不存在
    //        org.apache.shiro.authc.IncorrectCredentialsException密码错误
    
            return "redirect:index";
    
        }
    }
    

    浅尝docker

    虚拟机 vm vbox

    docker 性能远高于虚拟机,对于磁盘的占用极小,对于cup内存的占用也很小。

    docker采用沙箱机制。docker各个沙箱中的软件独立运行,互不干涉。每个沙箱都有自己的ip和端口

    docker镜像 我们可以从它的官方仓库下载各种镜像

    docker容器 安装的软件叫容器

    linux基本操作

    首先配置centos网络

    可以和主机互通 ping

    docker基本命令

    可以修改yum源为阿里云

    yum search docker

    yum install docker

    启动docker

    systemctl start docker

    查看以有的镜像

    docker images

    查看已有的容器

    docker ps -a

    删除镜像

    docker rmi 镜像名

    删除容器,如果容器运行中

    docker stop 容器id

    docker rm 容器id

    安装tomcat

    可以修改docker镜像为中国

    vi /etc/docker/daemon.json

    {

    ​ "registry-mirrors": ["http://hub-mirror.c.163.com"]

    }

    systemctl restart docker

    从官方仓库下载镜像

    docker pull tomcat:版本号(版本号可以省略,默认最新版)

    https://hub.docker.com/_/mysql?tab=tags

    启动tomcat

    docker run -d -p 8081:8080 tomcat

    -d后台运行

    -p 端口映射 宿主机端口:容器端口

    tomcat 镜像名字

    查看容器的ip

    docker inspect 容器id

    进入容器内部

    docker exec -it 容器id bash

    删除webapps

    rm -rf webapps

    将webapps.dist改名为webapps

    mv webapps.dist webapps

    退出容器

    exit

    重启容器

    docker restart 容器id

    我们启动两个tomcat

    然后修改 其中一个tomcat的默认页面,使我们能够区分俩个tomcat即可

    但是,docker容器内部没有vi/vim命令

    在容器内部执行

    apt-get update

    apt-get install vim

    如果你的网速更新比较慢,我们可以采用复制的方式

    退出docker

    将我们需要的文件复制到宿主主机上

    docker cp f0c40adac880:/usr/local/tomcat/webapps/ROOT/index.jsp /home

    在宿主主机上修改,完成后再复制回去即可

    docker cp /home/index.jsp f0c40adac880:/usr/local/tomcat/webapps/ROOT/

    重启容器

    docker restart f0c40adac880

    也可以实现文件修改。

    在你运行run容器的时候,加一个命令-v

    -v 宿主机的一个配置文件路径/home/xxx.conf 容器的配置文件 /etc/xxx.conf

    应该的对docker版本有要求

    安装nginx

    nginx两个作用:

    1/静态资源服务器

    开发时,我们一般动静分离部署

    一般使用nginx做静态资源服务器,为网站提供静态资源服务

    一般使用tomcat做动态资源服务器,提供具体业务服务

    docker pull nginx

    docker run -d -p 9090:80 nginx

    docker exec -it 容器id bash

    cd /etc/nginx

    该文件夹下的nginx.conf就是nginx的配置文件。

    user  nginx;
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    user  nginx;
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
        #tcp_nopush     on;
    
        keepalive_timeout  65;
    
        #gzip  on;
    
        include /etc/nginx/conf.d/*.conf;
    }
    
    

    include /etc/nginx/conf.d/*.conf;

    但是该配置文件中没有配置 nginx的信息,最后一行引入了另一个配置文件,在此文件中有nginx的具体配置

    将给conf文件复制出来

    docker cp c3a47fbcdebf:/etc/nginx/conf.d/default.conf /home

    vi /home/deafault.conf

    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;
    
        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    
    

    2/反向代理服务器

    配置nginx做反向代理服务器

    include /etc/nginx/conf.d/*.conf;

    nginx的真正配置文件就是上述路径中的default.conf

    修改 该文件

    upstream local_tomcat{
            server 172.17.0.3:8080;
            server 172.17.0.4:8080;
    }
    
    server {
            listen 80;
            server_name localhost;
            
            location / {
                    proxy_pass http://local_tomcat;
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header REMOTE-HOST $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
    }
    

    将default.conf复制回容器

    docker cp /home/default.conf c3a47fbcdebf:/etc/nginx/conf.d/

    重启nginx容器

    docker restart 容器id

    nginx其他配置方式请见博客:

    https://www.cnblogs.com/kinwing/p/11130281.html

    问题遗留:

    如何实现nginx集群化

    地区来访问不同的域名 bj.fang.com/sz.fang.com

    游戏,分区

    www.taobao.com

    微服务:

    300模块

    聚划算ju.taobao.com 20ip 50 ju.com cart.ju.com order.ju.com 抢购 服装 电器城。。。。

    安装mysql

    docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mariadb

    -d 后台

    -p端口映射

    -e 设置初始密码(不设置,不能启动)

    安装redis

    docker pull redis

    docker run -d -p 7006:6379 redis

    进入docker

    docker exec -it 24592a4df6d6 bash

    进入redis

    redis-cli

    接下来就是各种命令操作redis了。

    安装redis集群

    docker中的redis默认是没有配置文件的(redis.conf)

    redis默认不开启 集群模式,需要我们在redis.conf中配置。

    所以我们在启动集群的时候必须挂载宿主机中的redis.conf(提前配置好,开启集群模式)到redis中

    挂载命令-v 宿主机文件:容器中的位置

    我的docker中执行-v命令时总是报错,容器可以create,但是无法up;

    如果想执行-v而不报错,需要我们关闭系统的一个SELinux。

    vim /etc/sysconfig/selinux
    
    SELINUX=enforcing 改为 SELINUX=disabled
    
    安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。
    
    SELinux 主要由美国国家安全局开发。2.6 及以上版本的 Linux 内核都已经集成了 SELinux 模块。
    
    SELinux 的结构及配置非常复杂,而且有大量概念性的东西,要学精难度较大。很多 Linux 系统管理员嫌麻烦都把 SELinux 关闭了。
    

    然后重启centos系统。就ok了。

    下一步我们需要得到redis.conf文件

    wget http://download.redis.io/releases/redis-6.0.5.tar.gz
    tar -zxvf redis-6.0.5.tar.gz
    cd redis-6.0.5 
    就可以得到redis.conf文件
    

    下一步,配置redis.conf文件

    bind 127.0.0.1 可以 将其注释掉或者改成bind 0.0.0.0
    #启用集群模式 默认注释掉了 重点
    cluster-enabled yes 
    #超时时间appendonly yes
    daemonize yes 
    protected-mode no
    

    下一步运行docker redis容器,启动redis服务器,6台(3主3从)。下面 的命令只是启动了6个服务器,没有配主从等。

    docker run -p 7000:6379 -v /myredis/conf/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf
    docker run -p 7001:6379 -v /myredis/conf/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf
    docker run -p 7002:6379 -v /myredis/conf/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf
    docker run -p 7003:6379 -v /myredis/conf/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf
    docker run -p 7004:6379 -v /myredis/conf/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf
    docker run -p 7005:6379 -v /myredis/conf/redis.conf:/etc/redis/redis.conf -d redis redis-server /etc/redis/redis.conf
    

    下一步配置集群和主从

    首先查看6台服务器的ip地址,后面要用(inspect查看容器ip,grep过滤作用)
    docker inspect c69f55bda18b 3e0230701a05 af2c1524e494 d294113b8944 6ec9c7ff9118 a81b155cb051 |grep IPAddress
    
    -----------------------------------------------
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.7",
                        "IPAddress": "172.17.0.7",
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.6",
                        "IPAddress": "172.17.0.6",
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.5",
                        "IPAddress": "172.17.0.5",
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.4",
                        "IPAddress": "172.17.0.4",
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.3",
                        "IPAddress": "172.17.0.3",
                "SecondaryIPAddresses": null,
                "IPAddress": "172.17.0.2",
                        "IPAddress": "172.17.0.2",
    
    -----------------------------------------------
    
    
    然后启动集群,任意进入一台redis容器
     docker exec -it c69f55bda18b bash
     执行如下命令创建集群
    redis-cli --cluster create 172.17.0.2:6379 172.17.0.3:6379 172.17.0.4:6379 172.17.0.5:6379 172.17.0.6:6379 172.17.0.7:6379 --cluster-replicas 1
    
    #--cluster-replicas 1是配置一主一从,如果是2就是一主二从
    结果示意:有个yes需要输入一下
    ---------------------------------------------------
    Master[0] -> Slots 0 - 5460
    Master[1] -> Slots 5461 - 10922
    Master[2] -> Slots 10923 - 16383
    Adding replica 172.17.0.6:6379 to 172.17.0.2:6379
    Adding replica 172.17.0.7:6379 to 172.17.0.3:6379
    Adding replica 172.17.0.5:6379 to 172.17.0.4:6379
    M: 209df49459b4381369a6df9a1ec15cbad720569c 172.17.0.2:6379
       slots:[0-5460] (5461 slots) master
    M: 8e4e787885fe0af1419b7c2ef9dadb83b76d579e 172.17.0.3:6379
       slots:[5461-10922] (5462 slots) master
    M: b19e42dbf88969785e40784638b6386428c0d2b1 172.17.0.4:6379
       slots:[10923-16383] (5461 slots) master
    S: 8982c04e80b04a312a241f9ae68539160dc90e61 172.17.0.5:6379
       replicates b19e42dbf88969785e40784638b6386428c0d2b1
    S: 8141634b2b7eddc49494d9a6db1a54f355a2931a 172.17.0.6:6379
       replicates 209df49459b4381369a6df9a1ec15cbad720569c
    S: b4ecb477f53c59a3448286051778106e261ee3cf 172.17.0.7:6379
       replicates 8e4e787885fe0af1419b7c2ef9dadb83b76d579e
    Can I set the above configuration? (type 'yes' to accept): yes
    
    
    ---------------------------------------------------
    
    如何查看集群信息
    首先进入redis命令行内部
    执行:redis-cli
    进入后再执行 cluster info可以看到集群信息
    -----------------------------------------
    cluster_state:ok
    cluster_slots_assigned:16384
    cluster_slots_ok:16384
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:6
    cluster_size:3
    cluster_current_epoch:6
    cluster_my_epoch:2
    cluster_stats_messages_ping_sent:104
    cluster_stats_messages_pong_sent:89
    cluster_stats_messages_meet_sent:1
    cluster_stats_messages_sent:194
    cluster_stats_messages_ping_received:89
    cluster_stats_messages_pong_received:105
    cluster_stats_messages_received:194
    
    ------------------------------------------
    还可以查看节点信息
    执行:cluster nodes
    如下:
    -----------------------------------------
    8141634b2b7eddc49494d9a6db1a54f355a2931a 172.17.0.6:6379@16379 slave 209df49459b4381369a6df9a1ec15cbad720569c 0 1594916370000 5 connected
    8e4e787885fe0af1419b7c2ef9dadb83b76d579e 172.17.0.3:6379@16379 master - 0 1594916372700 2 connected 5461-10922
    8982c04e80b04a312a241f9ae68539160dc90e61 172.17.0.5:6379@16379 slave b19e42dbf88969785e40784638b6386428c0d2b1 0 1594916371673 4 connected
    b19e42dbf88969785e40784638b6386428c0d2b1 172.17.0.4:6379@16379 master - 0 1594916371000 3 connected 10923-16383
    b4ecb477f53c59a3448286051778106e261ee3cf 172.17.0.7:6379@16379 myself,slave 8e4e787885fe0af1419b7c2ef9dadb83b76d579e 0 1594916369000 6 connected
    209df49459b4381369a6df9a1ec15cbad720569c 172.17.0.2:6379@16379 master - 0 1594916371000 1 connected 0-5460
    
    -----------------------------------------
    
    

    下一步:使用集群

    使用 redis-cli -c该命令进入即可,一定要有-c,否则报错。

    127.0.0.1:6379> set a aaa
    -> Redirected to slot [15495] located at 172.17.0.4:6379
    OK
    172.17.0.4:6379> set b bbb
    -> Redirected to slot [3300] located at 172.17.0.2:6379
    OK
    172.17.0.2:6379> set c ccc
    -> Redirected to slot [7365] located at 172.17.0.3:6379
    OK
    172.17.0.3:6379> set d ddd
    -> Redirected to slot [11298] located at 172.17.0.4:6379
    OK
    172.17.0.4:6379> get a
    
    

    ok。

    redis

    redis概述

    nosql not only sql

    redis高度缓存 mongo数据库

    1/用redis做单点登录系统(分布式)

    2/做数据库层的上一层高速缓存层(内存)

    redis是基于内存的一种存储,使用key:value

    redis3.0之后开始支持分布式

    它支持存储的value类型相对更多:

    包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)

    字符串类型 string 512M

    散列类型 hash 2^32-1

    列表类型 list 2^32-1

    集合类型 set 2^32-1

    有序集合类型 zset

    redis支持持久化

    会生成一个文件,里面记录着所有的数据

    redis默认端口:6379

    redis数据存取

    redis命令大全参考:

    http://doc.redisfans.com/

    字符串类型:

    set name zhangsan

    get name

    keys *

    https://blog.csdn.net/qq_15071263/article/details/83576713

    select 1选择数据库,模式使用0号数据库,共16个

    del name

    incr num自增(点赞效果)

    decr num自减

    append name2 xxxx

    expire a 10(秒)

    ttl a 查看剩余时间(-2表示该键被删除)

    persist c让c的生存时间失效,不计时了。

    其他数据类型请见文档。

    springboot集成redis

    1/导包

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

    2/配置 ip 端口

    #redis
    spring.redis.host=192.168.1.3
    spring.redis.port=7006
    

    3./使用redis

    @RestController
    public class RedisController {
    
        @Autowired
        StringRedisTemplate template;
    
        @RequestMapping("redis")
        public void test (){
            //字符串
            template.opsForValue();
            //hash   map
            template.opsForHash();
            //list
            template.opsForList();
            //set 无序 不重复
            template.opsForSet();
            //有序set
            template.opsForZSet();
    
            template.opsForValue().set("aaa","bbb");
            String s = template.opsForValue().get("aaa");
            System.out.println(s);
    
            template.opsForValue().increment("age");
    
            //关于key的操作都在template中
            template.expire("aaa", Duration.ofSeconds(10));
            //关于value都在ops中
            Set<String> keys = template.keys("*");
            for (String ss : keys) {
                System.out.println(ss);
            }
    
    
            template.opsForHash().put("dog","name","ahuang");
            template.opsForHash().put("dog","age","2");
    
            System.out.println(template.opsForHash().get("dog","age"));
    
    
        }
    
    }
    

    springboot集成redis集群版时,连接超时。

    问题遗留。

    redis单点登录

    简单示例:(有点丑)

    <div>
        <input type="text" name="username" id="username">
        <input type="text" name="password" id="password">
        <button id="login">登录</button>
    </div>
    </body>
    <script src="webjars/jquery/3.5.1/jquery.js"></script>
    <script src="webjars/jquery-cookie/1.4.1/jquery.cookie.js"></script>
    
    <script>
        $("#login").click(function () {
    //        var token = $.cookie("token");
    
            $.ajax({
                url:"/login",
                type:"post",
                dataType:"json",
                data:{
                    username:$("#username").val(),
                    password:$("#password").val()
    //                token:token
                },
                success:function (data) {
    
                }
            })
        });
    </script>
    
    </html>
    

    ​ ```java

    @Controller
    public class LoginController {
    
        @Autowired
        StringRedisTemplate template;
    
        @ResponseBody
        @RequestMapping("login")
        public String login(String username, String password, HttpServletResponse response){
            //我们不真的去查数据库,模拟一下
            if (username.equals("张三")&&password.equals("123456")){
                //生成token  还要将用户数据变成json
    //            commons-loging
                String uuid = UUID.randomUUID().toString();
                String s = RandomStringUtils.randomNumeric(10);
                String token = uuid+s;
                Cookie cookie = new Cookie("token",token);
                response.addCookie(cookie);
    
                //在redis(集群)里存一份
                //k:v  token:user
    
    
                template.opsForHash().put(token,"username","张三");
                template.opsForHash().put(token,"age","18");
                template.expire(token, Duration.ofMinutes(30));
    
                return "success";
    
            }else {
    
                return "error";
            }
        }
    
        @RequestMapping("loginPage")
        public String loginPage(){
            return "login";
        }
    
    
    }
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    这是购物车
    </body>
    </html>
    
    @Controller
    public class CartController {
    
        @Autowired
        StringRedisTemplate template;
        //过滤器filtter
    
        @RequestMapping("cartPage")
        public String cartPage(HttpServletRequest request){
            //浏览器中所有的cookie
            Cookie[] cookies = request.getCookies();
            for (Cookie c : cookies) {
                System.out.println(c.getName());
                if (c.getName().equals("token")){
                    String token = c.getValue();
                    Boolean b = template.hasKey(token);
                    if (b){
                        return "cart";
                    }
                }
            }
    
            return "login";
    
        }
    
    }
    

    redis做缓存

    数据库层之上,应该有一个redis层

    只能放读的数据。

    数据的特点:变化周期小,例如淘宝的商品详情数据。

    模块化工程

    mysql

    mysql主从配置

    mysql读写分离

    zookeeper

    fastdfs分布式文件系统

    mycat数据库分布式系统

    git(github/码云)/svn

    相关文章

      网友评论

          本文标题:高级实训

          本文链接:https://www.haomeiwen.com/subject/clywlktx.html