高级实训

2020-07-26  本文已影响0人  Scincyc

微服务简介

分布式简介

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

上一篇下一篇

猜你喜欢

热点阅读