ssmpro-note

ssmpro
笔记2

2104-ssmpro 学习的内容目录
> spirngboot  vue  node.js  京淘  nginx  redis  mycat 

				# ssmpro2104本阶段学到的
				    *动态为属性赋值
				    springboot的开箱即用
				    mybatis-plus
				    StringUtils spring提供的字符串工具类
				    spirngmvc流程
				    @CrossOrigin
				    md5加密,登录
				    uuid秘钥,免登陆
				    token session/cookie
				    登录成功后跳转, 前端路由机制
				    层级菜单, 层级列表
				    mybatis分页查询
				    mybatisPlus日期数据自动填充
				    事务回滚
				    全局异常处理
				    商品分类列表查询, 一级二级三级, 使用map集合
				    新增两个表, 主键自动回显
				    文件上传
				    nginx  反向代理,负载均衡 策略
				    nginx图片回显(后端返回给用户url,回显时图片是url,使用nginx反向代理url到本地)
				    hosts 本地域名关联
				    tomcat集群 nginx配置 proxy_pass
				    linux部署 tomcat集群,nginx(web)
				# ssmpro2104本阶段学到的



# lombok 

# 框架
> springmvc : 接收,返回数据   交互
> spirng : 整合第三方框架   整合
> mybatis : 整合jdbc   持久化
> spirngboot : 简化spring框架操作   简化

springboot
    tomcat
    spirng
        spirngmvc controller
        service
        mybatis dao
  > 注解 :
        dao  接口--@Mapper   实现类--@Repository
        service   实现类--@Service
        controller  @RestController
# tomcat
> springboot中自带tomcat  spring中没有

# springboot 应用
  ># 1. maven 命令
    clean    清空target文件目录
    compile  编译maven工程
    install  项目打包

  ># 2. 坐标
    com.jt                          组Id 项目主目录
    springboot_demo1          项目名称 名称唯一
    0.0.1-SNAPSHOT                  依赖版本
   > 2.0 坐标作用
        唯一标识项目路径    项目打包路径   

  ># 3. pom.xml 文件
    添加jar包,依赖
   > 3.1 parent标签
        依赖于Springboot项目(框架) , 由spring官网维护 , 其中几乎定义了所有的框架与SpringBoot兼容的版本信息
        集中定义版本号
   > 3.2 dependencies 
        添加jar包, 使项目依赖jar包, 那项目中就有什么功能
   > 3.3 build
        起到的作用使项目打包依赖 插件

  ># 4. SpringBoot配置文件
   > 4.1 .properties
            key-value 结构   语法: key=value 例如: server.port=8614   都是字符串类型
            程序I/O读取该配置文件, 默认编码是ISO-8859-1 , 中文需要指定字符集
   > 4.2 .yml
            key-value 结构  语法: key:(空格)value
            层级结构 父子级语法缩进
            默认编码utf-8
            编辑springboot使其与第三方框架整合

  ># 5. 动态为属性赋值 类里   @Value
   > 5.1 使用yml配置文件 application.yml
            定义: userinfo: name: 吕晶1    定义在配置文件中 当springboot启动时会自动加载配置文件 
            使用: @value(${userinfo.name})
                  private String name;
            表达式: ${name} springel表达式 spel表达式 
                    加载配置文件, 数据加载到map集合中, spel表达式可以通过key获取map中的value并赋值
   > 5.2 properties 配置文件  user.properties
            定义: userinfo2.name2=吕晶2   使用: 使程序读到此文件 @PropertySource 根据路径,加载配置文件,交给spirng容器管理
                                                @PropertySource(value="classpath:/user.properties",encoding="utf-8") 描述类
            使用: @value(${userinfo.name})
                  private String name;

  ># 6. SpringBoot 核心机制: 开箱即用   
    只需导入特定的jar包文件, 则可以直接使用其功能
    Spring不行
    SpringBoot进行了框架的简化, 扩展了, 简化了配置信息的书写,加入jar包就能使用

  ># 7. 热部署, lombok
   > lombok链式加载  @Accessors(chain = true) 重写了set方法使set方法有返回值,使得set方法可以链式加载
        User user = new User(); user.setName("l"); user.setAge(23); user.setSex(1);  
        user.setName("lvj").setAge(23).setSex(1); 如何实现? 前一个返回该对象后面的就能继续调用
        public User setName(String name){
            this.name = name;
            return this;
        }
   > idea中lombok使用需要安装插件, 在linux中运行需要安装插件吗
        不要
        lombok在编译期有效, 编译后的.class文件已经生成对应的方法, 没有了lombok的注解
            项目发布时 .class文件打包为 .jar文件 , 不需要lombok环境

  ># 8. 测试
    代码联调:
        在测试中 使用创建controller对象,调用方法   
            但controller中依赖注入了service层代码
            不用SpringBootTest 会报错 原因: 创建使用的类的对象,没有依赖注入不能使用对象中的依赖注入 
    @SpringBootTest-降低代码联调  
        测试启动的是springboot工程,对于项目中使用的所有依赖注入创建的对象, 都可以使用
            Springboot依赖注入, 把所有对象放在-容器-中, SpringBootTest会从bean中获取需要的对象
            
## 程序是如何加载的
   > 启动类使用SpringApplication.run() 加载的是本类上的注解@SpringBootApplication
  ># 9. 容器加载规则  SpringBoot加载器顺序
    1) 启动类main方法启动程序, 
    2) 加载类的注解@SpringBootApplication
    3) 获取当前主类所在包(com.cy)
    4) 包扫描机制, 扫描的是类上的注解, 特定的注解所在类交给spring的容器管理ioc-di
    5) 容器中的结构 Map key-类名 value-对象   Map
    6) 使用容器中的对象: @Autowired依赖注入 容器中有注入成功
    7) 容器启动成功, 使用注入的对象即可调用类中的资源
    --启动类注解@SpringBootApplication, 包扫描, 容器Map, @Autowired--

  ># 10. SpringBoot 整合mybatis
   > 类: 主启动类

   > 1) yml 配置文件
    spring.datasource
        url : # useUnicode=true&characterEncoding=utf8  存数据取数据 utf8 <--> GBK编码 互转
              # serverTimezone=GMT%2B8  GMT+8  %2B代表+
              # autoReconnect=true  断线是否重连
              # allowMultiQueries=true  是否运行批量操作
        password: lvjing   # 密码使用0开头 要使用""包括  "01234"
    mybatis.type-aliases-package: com.cy.pojo    # 设置别名包
 
   > 2) 依赖注入 代理对象
        注入的是对象, 
        面向接口开发: 接口不能创建对象,Spring为接口创建代理对象,就是克隆一个接口创建对象
        代理: 根据原有对象的模型, 在运行期动态创建了一个一模一样功能的实例对象
        jdk默认代理  class com.sun.proxy.$Proxy67

   > 3) sql写法
        xml : 
            UserMapper.xml  
        注解 :
            @Insert("")
            @Delete("") 
            @Select("select id,name,age,sex from demo_user where id = #{id}")
            @Update("")



  ># 11. SpringBoot 整合  mybatis-plus  单表操作
    通过配置,单表的crud  mybatis增强工具
   > 我要用的方法     便利
        userDao
            .insert(user);   user中设置添加的值
            .deleteById(242);   
            .deleteBatchIds(list);  list中为删除的所有 id 
            .delete(queryWrapper); where条件
            .update(user,updateWrapper);  user为修改的内容, updateWrapper为条件
            .updateById(user);  user中设置id 和 要修改的值
            .selectById(247);
            .selectList(queryWrapper); queryWrapper.eq("name","lvjing"); 
   >1, 实现
            没有xml文件
        1) 依赖  mybatis-plus-boot-starter
        2) 编辑pojo实现对象 和  数据表 关系
            对象 映射到 表
                @TableName(value="demo_user") 
            属性 映射到 字段
                    @TableId(type = IdType.AUTO)  主键
                    @TableField(value = "name")   普通
                属性 与 字段(非主键)名一致, 注解可省略

        3) dao接口  继承公共的接口,获取常用crud操作
            BaseMapper

        4) yml 配置
            mybatis-plus: 
        
        5) 使用对象的方式操作数据库
            测试  直接使用api操作数据crud

        @TableName("user")
        public class User extends BasePojo implements Serializable{}

        @Mapper
        public interface UserDao extends BaseMapper {}

   >2, 类
        pom.xml  mybatis-plus-boot-starter
        pojo     User.java  --@TableName(value="demo_user")  @TableId(type=IdType.AUTO) @TableField(value="name")
        dao      UserDao.java --extends BaseMapper
        application.yml   mybatis-plus: 
        test     Api  --userDao.insert(user);
   >3, API
        insert
            
        select       参数   
            ById     1
            List     new QueryWrapper(user)  条件构造器 封装where条件 
            objs     null   只获取主键id的值
        delete
            ById     100  
        update
            ById     User   修改除id以外 所有不为空null的数据
                            > 修改 id=241 的 name为lvyingying
                            user.setId(241).setName("lvyingying");
                            userDao.updateById(user);
            update
                            > 修改 name=lv 的 name,age,sex
                            user.setName("lvyingying").setAge(99).setSex("男");
                            UpdateWrapper updateWrapper = new UpdateWrapper();
                            updateWrapper.eq("name","lv");
                            userDao.update(user,updateWrapper);


   >4, 条件构造器 where   QueryWrapper
      QueryWrapper queryWrapper = new QueryWrapper();
      1) 使用User对象
            User user = new User();
            user.setName("lvjing");
            QueryWrapper queryWrapper = new QueryWrapper(user);    
            System.out.println(userDao.selectList(queryWrapper));

      2) name=lvjing 直接传参数, 不使用User对象    eq是=  
            QueryWrapper queryWrapper = new QueryWrapper();    
            queryWrapper.eq("name","lvjing").or().eq("sex","女");
            System.out.println(userDao.selectList(queryWrapper));

      3) age>18 且 sex=女
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.gt("age",18).eq("sex","女");
            System.out.println(userDao.selectList(queryWrapper));

      4) 常用逻辑运算符 
            = eq, > gt, < lt, >= ge, <= le, != ne 
            
      5) 关键字 
            like   1. like "%lv%"--queryWrapper.like("name","lv")  2. like '%lv'--queryWrapper.likeLeft("name","lv");
            in     1. queryWrapper.in("id",236,237,238);           2. Integer[] ids = {236,237,238}; queryWrapper.in("id",ids);
            order by       where sex='男' order by age desc   queryWrapper.eq("sex","男").orderByDesc("age");
            group by

   > 动态sql
        .eq(boolean condition, R column, Object val)
        select * from demo_user where age > 20 and sex = '男'
            queryWrapper.gt(ageBoo,"age",age).eq(sexBl,"sex",sex);          Integer age = 18;String sex = "女";

                boolean ageBoo = age != null;
                boolean sexBoo = sex != null && sex.length() > 0;
                boolean sexBl = StringUtils.hasLength(sex);


# 可变参数类型 
    放在参数里的最后   
    test(String name, Integer age, Integer... grade)

# StringUtils  
    org.springframework.util.StringUtils; spirng提供的,在spring框架中都可以用
        boolean sexBl = StringUtils.hasLength(sex);  判断sex是否为 空 或 null

  ># 12.springmvc
   > 项目结构
    pom
    .yml   type-aliases-package: com.lvjing.sys.pojo
    pojo 实体一般实现序列化接口 implements Serializable 
    dao  使用mybatis-plus 继承接口 extends BaseMapper 
         启动类中@MapperScan("com.lvjing.sys.dao") 为dao接口创建代理对象
   
  ># 13.controler 注解
        @PathVariable        @RequestBody  @ResponseBody
        1. @PathVariable  请求url为RestFul格式 http://localhost:8614/user/findById/{id}
                @GetMapping("findById/{id}")
                public User find(@PahtVariable Integer id){}

                 @DeleteMapping("/user/{id}")
                public void deleteUser(@PathVariable Integer id){}

        2. @RequestBody    前端post/put请求传递后端 json串格式   注解将JSON串格式转换为User对象
                @PostMapping("insert")
                public int insert(@RequestBody User user){}

                 @PutMapping("updateUser")
                public void updateUser(@RequestBody User user){}

        3.RestController
            返回值都是json串

        4.CrossOrigin
            跨域 url/ajaxurl

  ># 14.vue






    ># 16.servlet机制
        Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
        概念: java实现前后端数据交互的一种机制
        核心对象: Request对象(存储提交的数据)   浏览器 -> java后端
                 Response对象(服务器端返回数据信息)  java后端 -> 浏览器

> 后端路由 / 后端返回页面  页面在class中写
    @Controller
    配置: mvc-

  ># 17.springmvc 执行流程/调用流程图
> 组件
        1. 前端控制器 DispatcherServlet 实现请求的流转
        2. 处理器映射器 实现了请求路径与方法之间的映射.
        3. 处理器适配器 处理器的管理器 内部有N个处理器. 针对不同的用户请求 调用不同的处理器完成任务
        4. 视图解析器 直线页面路径的拼接
> 父子容器
        父子容器概念:
        1.Spring容器(内存中的一大块空间)由于IOC/DI的机制,可以作为第三方的管理者 所以作为父级.
        2.SpringMVC容器,其中只负责Controller层的相关的对象的管理.

        说明: 当SpringMVC容器启动时,提前将SpringMVC中的所有请求路径方法方法完成映射.
> 流程
        1. 用户发起请求时,第一步经过前端控制器,

        2. 但是前端控制器 只负责请求的转发和响应.不做任何业务处理.将请求转发给处理器映射器.

        3. 处理器映射器接收到前端控制器的请求之后,查询自己维护的服务列表信息.
        如果服务列表中没有这个URL的key. 该程序不能处理用户的请求,则返回特定数据,前端控制器接收之后响应用户404.
        如果服务列表中有该URL key 则说明请求可以正常执行. 将该方法的对象返回给前端控制器.

        4. 前端控制器将返回的方法进行接收,但是由于前端控制器只负责转发和响应,不能直接执行该方法.所以交给处理器适配器执行.

        5. 处理器适配器根据方法的类型(xml配置文件/注解/其他方法),处理器适配器在自己的处理器库中挑选一个最为合适的处理器去执行该方法. 当处理器执行该方法时标识业务开始. 将最终的处理的结果通过ModelAndView对象进行包裹,返回给前端控制器.
        ModelAndView: Model: 代表服务器返回的业务数据 View: 服务器端返回的页面的名称

        6. 视图解析器 将View中的数据进行解析 拼接一个完整的页面路径 前缀/hello后缀

        7. 视图渲染: 将数据与页面进行绑定. 这样用户就可以在页面中看到具体的数据.

        8. 由于现在流行前后端分离. 所以SpringMVC省略了视图解析和视图渲染.只有前5步. 核心注解: @ResponseBody 省略6-7步







  ># 15.jt项目

    前端, main.js - App.vue - router/index.js - component/Login.vue

> 1. 项目结构
        1) 启动类   @MapperScan("com.jt.sys.pojo")
        2) pojo     @Accessors(chain=true)  implements Serializable
        3) controller   @CrossOrigin

> 2. 用户登录操作 校验
   > 加密方式
        MD5加密/MD5Hash/sha1
        String md5DigestAsHex = DigestUtils.md5DigestAsHex(password.getBytes());
   > uuid
        32位16进制数  16^32   (2^4)^32   2^128   3.4*10^38
        时间戳进行的hash, 毫秒
        String uuid = UUID.randomUUID().toString().replace("_","");

> 3. 后端返回 token 前端需要保存, 如何存储?
      . Session-会话控制/会话机制 : 存储用户信息(所需属性和配置), 用户会话存在期间, 信息一致存在
                    当用户在app中的网页之间跳转时, 存储在Session对象中的变量不会丢失, 在整个用户会话中保存下来  
                    * 短时间内(会话期间)有效
                            
      . Cookie- : 
                    网站识别用户身份, 将session中的信息保存到计算机本地, 暂时或永久保存
                    加密的数据
                    * 一段时间内有效 例如:七天免密登录
      .. 例如:
                    session 安全  银行, 财务, 员工  
                    cookie        腾讯会员
      .. 使用: 
                    前端: 
                      session
                        //获取用户token信息(后端返回的)
                        let token = result.data
                        window.sessionStorage.setItem("token",token)
                     cookie
      .. 查看:
                    浏览器: 
                        F12 Application/Session Storage

      ...解决 登录之后(页面跳转)的用户信息展示在首页中, 
      
> 3. 登录成功首页跳转    前端
        vue elementui   this.$router.push("/home")
        路由中添加 /home 组件

> 4. 左侧菜单 权限
        一级菜单 二级菜单
        先把一级菜单查出来,
        根据一级菜单的id(二级菜单的parentid)查找对应的二级菜单, 
        把查找出来的二级菜单放到对应的一级菜单中,
> 5. 分页查询  展示用户信息
        * 1. mybatis
        pageResult  query/pageNum/pageSize/total/rows
        使用mapper映射文件 sql进行分页查询  limit (pageNum-1)pageSize,pageSize   limit 起始位置,条数
        * 2. mybatisplus
                           配置类
        @Configuration
        标识是一个配置类 代替xml文件
        分页
            // xml 标签管理,将对象给Spring管理  
            // 配置类 方法管理,将返回值给Spring管理 @Bean

            /**
            * MybatisPlus分页
            *      设定一个拦截器, 将指定的sql 动态拼接
            */
            // 最新版
            @Bean
            public MybatisPlusInterceptor mybatisPlusInterceptor() {
                MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
                interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
                return interceptor;
            }

> 6. mybatis-plus 数据自动填充   
        日期 添加
        https://mp.baomidou.com/guide/auto-fill-metainfo.html
        1. pojo 要自动填充数据的
            @TableField(fill = FieldFill.INSERT)
	        private Date created;	//表示入库时需要赋值
        2. 配置类
            实现 MetaObjectHandler接口 
            重写方法  入库操作  更新时操作
            方法: //setFieldValByName(arg1,arg2,arg3)
                    //arg1: 自动填充的字段名称   arg2: 自动填充的值   arg3: metaObject 固定写法

> 写方法时要考虑的问题

# 不知道的
> 7. 控制业务层事务    deleteById(id)   删除的 回滚    事务    
. 例如 业务层  数据删除成功,但方法失败
    userDao.deleteById(id);  成功
    int i = 1/0;  失败
    整个方法失败, 但数据删除成功
. 原子性,一个方法中的业务,要么同时成功,要么同时失败 
. 注解 @Transactional  Spring中事务控制
    核心: AOP中的@Around通知,实现对事物控制
    @Around: 环绕通知, 业务执行前.开启事务控制-执行目标方法-业务执行后.成功`提交/失败`回滚
    用法: 写在要使用事务的方法上
    事务策略: 1.运行时异常,回滚  算数,空指针,数组下标越界  5-7个
             2. 检查异常(编译异常),不回滚  Exception, 程序已经提示的异常,程序员自己处理,spring不管理
    属性: rollbackFor 遇到什么类型异常 回滚 
          noRollbackFor  遇到什么类型异常 不会滚 
          使用默认策略 
. @Transactional  修改.删除.更新

> 8. 根据AOP定义全局异常处理 机制
. 不能保证所有操作都正常, 使用功能try-catch异常, 但代码冗余
. 解决代码冗余, spring4的全局异常处理
. springmvc的全局异常处理类 advice/GlobalExceptionHandler
. 注解: @RestControllerAdvice 
        Around通知, 放回json串, 捕获的是controller层异常, 其他层会抛给controller
        @RestController/@Controller 描述的类中发生异常且没有处理, spring会查找注解@RestControllerAdvice描述的类, 进行异常处理
. 类: @RestControllerException 描述 class GlobalExceptionHandler
. 方法: @ExceptionHandler 描述 JsonResult doHandlerRuntimeException(Exception e){}
            e.printStackTrace();// 打印
            return new JsonResult(201,"",e);

> 9. 商品分类列表查询  -- for                内存数据结构                   运行速度
1. 商品分类表, 1级菜单 > 2级菜单 > 3级菜单 
2. 优化 查询速度
    分页
    查询一次,使用map集合
    https://blog.csdn.net/qq_40055619/article/details/118611141

> 10.123
    端口占用: netstat -ano | findstr "8091"   | 管道 先执行前面再执行后面

> 11. 商品新增  商品详情信息入库,两个表添加数据
. 新增的数据有两部分 1.商品item 2.商品详情   > 前端传入数据  > 后端使用封装了item和itemdesc的ItemVO接收
. 新增, 两个新增操作
    .. 主键自动回显功能
    问题; item新增的数据id 要和itemDesc新增的id一样,  
    解决:  0不行  直接使用查询, 把刚刚新增的查一次得到id  -这种方式存在问题, 如果有相同的数据 id就不一样了
          1. mybatis的主键自动回显功能  新增之后把新增的数据的id回显
                
          2. mybatis-plus 实现了主键自增功能  新增之后id就有值了
                itemDao.insert(item); 之前 item的id为空, 之后 item的id为新增数据的id
                item.getId() 这里就有值了

> 12.富文本 vue-quill-editor

> 13. 文件上传
    前端: http://localhost:8614/file/upload
    后端: 

存储文件: 文件放在本地目录, 
    1. virtualPath 存本地实际路径,不包含磁盘信息
    2. urlPath url访问, 其他人通过此url访问, 看到文件
    3. fileName  控制文件上传后的文件名
缓冲流一次搬运多大的字节效率最高?       1024
业务参数:  MUltipartFile 私密性
文件上传:
    前端 el-upload 上传文件
    后端 把文件保存在指定目录中  file.transferTo(new File(path))
    数据库 一条记录保存对应的文件目录, 当要查看/使用时通过路径调用指定目录的文件
> 上传
    1. 验证文件的类型, 图片 文件后缀, 正则  ^.+\\.(jpg|png|gif)$
    2. 进一步验证是否是图片, 使用图片特有的特征, 具有 宽高, 
    3. 把文件放在一个目录下, 检索费时间, 分目录存储  方法: 1.按时间 2.hash(hash存在问题-某些可能会被经常访问,某些不会被访问到)
    4. 文件名 不重名, uuid
    5. 实现文件上传  拼接全路径,上传
    /**
     * 实现上传:
     *      1. 验证上传文件是图片--文件后缀   ..校验字符串--正则表达式  木马.exe.jpg  图片特有--分辨率
     *      2. 防止恶意攻击, 验证图片是否有分辨率
     *      3. 文件分目录存储  1)时间-一天一个  2)8位16进制hash xx/xx/xx/xx
     *          hash: 造成数据分配不均, 可能会有某些经常被访问, 而有些不被访问
     *      4. 文件名 重名  uuid
     *      5. 实现文件上传
     *          拼接全路径, 完成上传
     *
     * 实现动态赋值:
     *      编辑配置文件: image.properties
     *          localDirPath     preUrlPath
     *      导入 image.properties配置文件
     *.          @PropertySource(value="classpath:/image.properties",encoding="utf-8")
     *.          @Value("${file.localDirPath}")
     *
     * 实现删除:
     *      deleteFile   参数: ImageVO-VirtualPath
     *
     * 实现预览:
     *
     * 上传两份相同的, 本地中会有两份, ????
     */


     // 上传路径   优化: 使用配置文件动态属性赋值
    @Value("${file.localDirPath}")
    private String localDirPath;
    // 虚拟路径
    @Value("${file.preUrlPath}")
    private String preUrlPath;

    @Override
    public ImageVO upload(MultipartFile file) {
        // 1. 校验图片类型是否正确, 正则   a.jpg
            // 获取文件名
        String fileName = file.getOriginalFilename();
        fileName = fileName.toLowerCase(); // 全部转换为小写
            // 正则
        String regex ="^.+\\.(jpg|png|gif)$";
                // bug  正则中  .JPG   java区分大小写
        if (!fileName.matches(regex)){return null;}

        // 2. 校验文件是否为恶意程序,  判断文件是否有分辨率 宽 高
            // 将文件转换为图片对象
        try {
            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());  // file转换为图片对象
                // 获取宽高
            int height = bufferedImage.getHeight();
            int width = bufferedImage.getWidth();
            if (height==0 || width==0){return null;}

        // 3.文件分目录存储
            // 按时间分配
            String dateDirPath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
            // 文件根目录
            String localDir = localDirPath+dateDirPath;
            // 目录不存在,创建
            File dirFile = new File(localDir);
            if (!dirFile.exists()){dirFile.mkdirs();}

        // 4.文件名, 重名  uuid 2^128
            // 文件名
            String uuid = UUID.randomUUID().toString().replace("-","");
            // 后缀
            int index = fileName.lastIndexOf(".");
            String fileType = fileName.substring(index);
            // 文件名+后缀   089aa0fe087a4ebaa896ee7ce1314a08.png
            String realFileName = uuid + fileType;

        // 5.文件上传
            // 拼接全路径  目录/文件名   localDir realFileName
            String localFilePath = localDir + realFileName;
            // 文件上传
            file.transferTo(new File(localFilePath));

/**
 * 目录 :
 *      本地磁盘: D:\AIT\Java\eSSMPro\ideassmprotwo\h-jt\src\main\resources\static\images
 *      时间分配: \2021\07\13\
 *      文件名: 089aa0fe087a4ebaa896ee7ce1314a08.png
 *      文件本地路径: D:\AIT\Java\eSSMPro\ideassmprotwo\h-jt\src\main\resources\static\images\2021\07\13\089aa0fe087a4ebaa896ee7ce1314a08.png
 *
 *      虚拟前缀: http://image.jt.com
 *      没有盘符: \2021\07\13\089aa0fe087a4ebaa896ee7ce1314a08.png
 *      虚拟路径: http://image.jt.com/2021/07/13/089aa0fe087a4ebaa896ee7ce1314a08.png
 */


        // 返回imageVO
            String imageVOVirtualPath = dateDirPath+realFileName; // 没有磁盘路径
            String imageVOUrlPath = preUrlPath+imageVOVirtualPath; // 虚拟路径
            String imageVOFileName = realFileName; // 文件名
            return new ImageVO(imageVOVirtualPath,imageVOUrlPath,imageVOFileName);

        } catch (IOException e) {
            e.printStackTrace();
            return null; // 终止程序
        }
    }



# nginx
> 14.nginx 
1. 反向代理机制   服务端代理
    自己理解: 
        用户发起请求, 为了保护目标服务器中资源的安全性, 在用户与目标服务器之间使用代理服务器, 
        用户发起请求访问代理服务器代理服务器转发请求给目标服务器, 目标服务器把数据给代理服务器, 代理服务器再把数据给用户
        保证里目标服务器的数据安全, 也保证了用户的安全, (用户不知道目标服务器真正的访问请求, 目标服务器也不知道用户的信息)

    不知道原始服务器, 不知道真正的资源, 安全
    反向代理服务器  用户与目标服务器之间,    用户通过访问反向代理服务器就能获取目标服务器资源, 通常用在web加速器(降低了网络和服务器的负载,提高了访问效率)
    特点:
        1. 反向代理服务器 介于用户和目标服务器之间
        2. 用户以为反向代理服务器就是目标服务器 
        3. 用户不知道真正的请求地址
        4. 用户与目标服务器 互相不知道
        5. 反向代理服务器中存储的是 用户的访问地址与目标服务器真正的访问地址的映射
    步骤:
        1. 用户向代理服务器发送请求,(以为代理服务器就是真实目标服务器)
        2. 代理服务器接收请求时,根据自己的映射文件,重新发起新的请求 访问真实的目标服务器.
        3. 根据映射路径,查找真实的服务器资源.
        4. 获取资源返回给代理服务器.
        5. 代理服务器将资源交换给用户.

2. 正向代理机制   客户端代理
    自己的理解:
        客户端才能正向代理, 用户访问原始服务器受限(某种原因), 正向代理在用户和原始服务器中间, 用户可以访问正向代理服务器 正向代理可以访问原始服务器
        用户(指定目标)通过访问正向代理, 正向代理访问原始服务器, 获取数据

    清楚知道要访问的资源是啥, 由于某些机制受限  用户访问
    特点:
        1. 正向代理介于用户和目标服务器之间
        2. 用户很清楚要访问原始服务器的资源是什么
        3. 一般正向代理实现的是网络之间的通信

正向代理和反向代理服务器:
        用户---(正向代理)--->某某服务器------>反向代理服务器------>{业务服务器1,业务服务器2,...}
        客户端代理: 保护了用户信息
        服务端代理: 保护了服务器信息


3. nginx
    概述:
        高性能http和反向代理web服务器, C语言开发, 
        Nginx是一个主流的 反向代理服务器 / 负载均衡服务器
    特点:
        1. 占用内存少, 启动一个服务运行内存不到2M,
        2. 并发能力强, 5万/秒 实测:2-3万/秒
    科普: 单台tomcat服务器并发能力 220/秒 JVM调优 增大JVM运行内存空间
    配合服务器监控.根据当前硬件设备进行优化. 经过JVM调优之后的tomcat服务器 可以达到 1000/秒

4. nginx安装
    下载解压, .exe文件 运行, 运行之后两个进程
    进程: 主进程(主要提供反向代理服务) 守护进程(防止主进程意外关闭)

5. nginx命令
    启动: start nginx          只负责启动, 没有报错信息
    重启: nginx -s reload      重启服务, 含有报错信息, 没有报错信息nginx启动成功
    停止: nginx -s stop

6. nginx配置文件 nginx.conf
    http{
        # 每一个反向代理服务都是一个server     http://localhost:8704/
        server {
        # 监听端口
            listen       8704;
            # 拦截用户访问路径
            server_name  localhost;

            # 反向代理具体配置项  location (具体配置) / (拦截所有请求)
            # root 代表目录html
            # index 默认访问页面
            location / {
                root   html;
                index  index.html index.htm;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

> 14.图片回显/浏览器预览
1. 用户使用的url地址: http://image.jt.com/2021/07/13/089aa0fe087a4ebaa896ee7ce1314a08.png    
   本地路径:         D:\AIT\Java\eSSMPro\ideassmprotwo\h-jt\src\main\resources\static\images\2021\07\13\089aa0fe087a4ebaa896ee7ce1314a08.png
   没有映射url和本地路径
2. 解决:
    用户访问http://image.jt.com  映射到D:\AIT\Java\eSSMPro\ideassmprotwo\h-jt\src\main\resources\static\images
3. 反向代理
    配置 nginx.conf  图片的映射server
    server{
        listen        80;
        server_name   image.jt.com;
        location / {
            root   D:\AIT\Java\eSSMPro\ideassmprotwo\h-jt\src\main\resources\static\images;
        }
    }
4. 图片反向代理原理
    image.jt.com 的域名 发到了公网, 不能访问
    解决: HOSTS文件 -主要在本机实现 域名与ip的映射 image.jt.com 与 172.18.6.35 
    HOSTS文件位置: C:/windows/system32/drivers/etc/hosts
    HOSTS文件:
        127.0.0.1 localhost
        127.0.0.1 image.jt.com
    重启nginx
    权限问题:
        属性-安全-编辑当前用户的权限
        文件属性-高级-更改权限-添加当前用户的权限

反向代理实现原理自己理解:
    文件的上传(本地)目录--自己设置filePath
    用户访问的url--自己设置virtualPath
    . 通过filePath把上传的文件保存到本地, 返回给用户virtalPath路径进行访问
    nginx实现 反向代理  image.jt.com 和  D:\AIT\Java
    . 通过配置文件nginx.config 中的 server(是一个反向代理服务) 
    . nginx只要配置好 启动, 当使用到反向代理是会自动映射, 不用在自己的服务中配置

    域名问题:
        image.jt.com的域名 会在公网汇总请求, 要在自己电脑上使用
        配置hosts文件 127.0.0.1 image.jt.com

> 15.nginx域名代理      前后端服务发布  打包
1.项目 编译
    后端: 8614   为前端提供数据支持
    前端: 8080  借助tomcat服务器  生产环境中前端是静态资源(需要打包发布)
2.域名访问
    前端: 访问前端http://web.jt.com:8080/
    后端: 访问后端http://manage.jt.com:8614/
    前端访问后端: http://manage.jt.com:8614/
3.前端打包->静态资源文件
    脚手架 build
    文件目录 dist
4.前端访问
    使用 http://web.jt.com 访问打包后dist中index.html文件
        反向代理  nginx.conf
            server{
                listen          80;
                server_name     web.jt.com;
                location / {
                    root        dist;
                    index       index.html;
                }
            }
        hosts    域名 web.jt.com
            # 访问前端域名
            127.0.0.1       web.jt.com
5.后端访问
    http://manage.jt.com  反向代理 localhost:8614
    nginx
        server{
            listen          80;
            server_name     manage.jt.com;
            location / {
                proxy_pass       http://localhost:8614;
            }
        }
    hosts
        # 访问后端域名
        127.0.0.1       manage.jt.com
6.后端打包
    maven
        clean
        install
    8614/8615

7.整合
    前端放在nginx中, 启动nginx, 访问前端域名就能访问前端
    后端打包,

nginx.conf 反向代理
    http{
        # 图片代理  图片回显
        server{
            listen          80;
            server_name   image.jt.com;
            location / {
                root   D:/AIT/Java/eSSMPro/ideassmprotwo/h-jt/src/main/resources/static/images;
            }
        }

        # 前端代理  web.jt.com 访问 京淘首页
        server{
            listen          80;
            server_name     web.jt.com;
            location / {
                root        dist;
                index       index.html;
            }
        }

        # 后端代理  前端请求 manage.jt.com  访问后端localhost:8614
        server{
            listen          80;
            server_name     manage.jt.com;
            location / {
                proxy_pass       http://localhost:8614;
            }
        }
    }
.hosts    域名   
    # 京淘项目
    # 访问图片域名
    127.0.0.1       image.jt.com
    # 访问前端域名
    127.0.0.1       web.jt.com
    # 访问后端域名
    127.0.0.1       manage.jt.com

> 16.tomcat服务搭建   部署tomcat服务器集群   nginx使用
原因: 
    nginx 2万/秒, 但是8614服务器只能1000/秒, 
解决: 
    搭建后端服务器集群, 分担压力, 端口号
1.集群:
    物理结构, 多态服务器(物理服务器), 一台物理设备可以部署多个tomcat服务, 
2.nginx的负载均衡: 
    一个 nginx 多个服务器 , 要请求哪1个服务器, 就是负载均衡
    upstream tomcats{}
        # 负载均衡  轮循
        upstream tomcats {
            server localhost:8614;
            server localhost:8615;
        }
        server {
            listen 80;
            server_name  manage.jt.com;
            location / {
                proxy_pass  http://tomcats;
            }
        }
3.权重机制
    性能高的服务器, 让其经常访问
    weight=6
        upstream tomcats{
            server localhost:8614 weight=1;
            server localhost:8615 weight=9;
        }
4.iphash
    用户与服务器绑定   -用户指定服务器进行访问
    upstream tomcats {
        ip_hash;
        server 127.0.0.1:8615 weight=1;
        server 127.0.0.1:8614 weight=9;
    }
 iphash算法
    hash(ip:port)%2  余数

5.nginx高可用
高可用HA 
服务器宕机, 实现自动化故障迁移, 无需人为干预

6.nginx策略
    一个服务器访问不同, 自动访问下一台
    轮循
    权重
    iphash
    插件

7.nginx属性
    down     该属性标识的服务器, nginx永远不会访问此服务器
    backup   设置备用机, 正常不提供服务, 如果其他设备宕机, 则访问该备用机
    max_fails=1        访问失败的最大次数
    fail_timeout=60s   失败的超时时间, 在超时时间范围内, 不会再次访问故障机

> 17.linux
1.命令
    ip addr
    clear
    pwd   当前目录位置
    tab键   自动补齐
    cd    切换目录
    cd, cd ~, cd /, cd ., cd .., 
    cd /usr/local/src
    ls   展示文件目录,    ll 总用量
    mkdir   创建目录,  mkdir abc ,  mkdir -p a/aa/aaa  多层目录, mkdir -m 777 c 权限为777的目录,  
    rmdir 删除非空,
    rm  删除文件, rm a.txt, rm -f a.txt, rm -r c, rm -rf c,    rm删除文件, -f没有提示, -r递归 删除目录(非空也行),       rm -rf * 删除本目录所有
    vi/vim   编辑文件,  i 插入,   esc :wq 保存退出,   esc u 撤销,  esc :set nu 展示行号,    esc :q!   感叹号强制退出,     :quit 退出
    cp 复制 , cp a.txt a.txt.cp 复制文件,  cp -r a b复制目录,  
    mv 移动 , mv b.txt b b.txt移动到b,  mv a.txt b.txt 改名,
    tar包  -cvf -zcvf打包 -xvf解压,
            tar –cvf n.tar ./* 压缩当前目录下的所有文件和目录,文件名为n.tar
            tar –xvf n.tar 解压压缩包中的文件到当前目录(如果长时间未解压成功 Ctrl+C推出)
            tar –cvzf m.tar.gz ./* 压缩文件
            tar -zxvf m.tar.gz		解压m.tar文件到当前目录

2.环境搭建
    目录   /usr/local/src/
    jdk   解压 tar -xvf n.tar
          配置环境变量:  vim /etc/profile
                # 设定jdk环境
                export JAVA_HOME=/usr/local/src/jt/jdk/jdk1.8
                export PATH=$JAVA_HOME/bin:$PATH
                export CLASSPATH=.:$JAVA_HOME/lib

          使其作用:      source /etc/profile

    linux配置文件      vim   /etc/profile/   

3.数据库
    yum install mariadb-server
    yum 像是linux的应用商城
     yum  clean   all                 清空已安装文件   如果下载失败之后执行的.
    
    1.   启动命令        systemctl  start  mariadb
	2.   重启命令        systemctl  restart  mariadb
	3.   关闭命令        systemctl  stop  mariadb
	4.   设定开机自起    systemctl  enable mariadb 
	5.   关闭开机自起    systemctl  disable mariadb 

    数据库初始化:  mysql_secure_installation
    登录: mysql -uroot -proot
    导入数据库: source /x/x/x/x/xxxx.sql
    linux的数据库权限
        mysql库
            select host,user,password from user;
            update user set host = "%" where host = "localhost";
                % 代表任意ip
        刷新数据库权限
            flush privileges;

4.liunx防火墙
    firewall-cmd --state  防火墙状态
    systemctl enable/disable firewalld.service   防火墙开机自启/关闭
    systemctl start/stop firewalld.service       手动开启/关闭防火墙
    手动开放防火墙端口
        firewall-cmd --list-ports  检查防火墙开放的端口
        firewall-cmd --query-port 80/tcp  80端口是否开放
        firewall-cmd --zone=public --add-port=80/tcp --permanent     开启防火墙端口
        firewall-cmd --zone=public --remove-port=9090/tcp --permanent   移除端口
                –zone #作用域
                –add-port=80/tcp #添加端口,格式为:端口/通讯协议
                –remove-port=80/tcp #移除端口,格式为:端口/通讯协议
                –permanent #永久生效,没有此参数重启后失效
    firewall-cmd --reload 重启防火墙

5.部署tomcat服务
    修改原始服务
        1.文件上传地址  改成linux本地目录
    打包后端服务
        8614.jar
    复制到linux
        父目录 java -jar 8614.jar & 运行

> 18.tomcat集群   后端服务器集群
1.启动8614/8615
    java -jar 8614.jar & java -jar 8615.jar &
    jps linux检索java服务项所有进程号
    kill pid号(进程号)  常规   linux手动关闭某个服务的进程项,杀进程     kill -15 pid号 强制   kill -9 pid号 无法逆转

2.使tomcat服务器 后台运行   关闭终端后服务不关闭
    nohup java -jar 8614.jar linux后台运行
    日志单独保存
        nohup java -jar 8615.jar => logs/8615.log

3.关闭进程
    ps -ef 查看所有进程项
    ps -ef | grep java    | 管道,以第一个的结果作为第二个的条件    ps -ef 的结果  作为grep java 的参数

4.查看日志
    cat 输出所有
    more/less 分页  空格..下一屏  q..退出 
    tail -10 8614.log   只展现后面几行
    tail -f 8614.log   动态查看日志

5.脚本启动服务
    vim start.sh   创建脚本文件
    内容:
        #!/bin/sh
        nohup java -jar /usr/local/src/jt/jtservice/8614.jar => /usr/local/src/jt/jtservice/logs/8614.log &
        nohup java -jar /usr/local/src/jt/jtservice/8615.jar => /usr/local/src/jt/jtservice/logs/8615.log &
    执行:
        sh start.sh
    
    ./ 当前目录  .当前 /目录

> 19.linux部署 nginx
1.nginx安装包
    nginx-1.21.1.tar.gz
    tar -xvf nginx-1.21.1.tar.gz
2.文件说明
    /usr/local/src/jt/nginx/nginx-source    源文件目录, 安装配置nginx
3.nginx安装
    配置nginx:
        configure 脚本文件  执行   
        ./configure
        nginx path : /usr/local/nginx
    编译:
        make  nginx配置文件所在目录
    安装:
        make install
    检查:
        whereis nginx
    启动:
        /usr/local/nginx  目录下
        ./nginx  运行
        ./nginx -s reload
        ./nginx -s stop
    查看:
        ps -ef | grep nginx
4.nginx部署web
    image      web.jt.com     manage.jt.com
    把前端dist目录放到nginx目录下 /usr/local/nginx
    conf目录 nginx.conf
        # 前后端集群配置 server{}
    修改hosts文件, 用户在windowsxia访问
            C:\Windows\System32\drivers\etc\hosts
        # 京淘项目   linux
        # 访问图片域名
        192.168.126.129       image.jt.com
        # 访问前端域名
        192.168.126.129        web.jt.com
        # 访问后端域名
        192.168.126.129       manage.jt.com


# 项目部署在linux中
>后端
   jdk 
   mysql 
   服务打包运行   8614.jar 8615.jar  start.sh(脚本运行)
>前端
    nginx:
        下载nginx的linux安装包  nginx-1.21.1.tar.gz
        复制到linux解压
        执行nginx脚本./configure, 编译make, 安装make install, 启动/usr/lcoal/nginx/sbin  ./nginx
    web服务:
        把打包后的web目录复制到nginx安装后的目录中 /usr/local/nginx
    nginx配置web:
        修改conf/nginx.conf  域名映射server{listen ;server_name ;location / {root ;index ;} }
>用户访问
    用户在windows下访问, 域名关联
    修改hosts文件
        192.168.126.129  web.jt.com


# 二阶段整理
> 框架梳理
    1.环境
        idea, maven
    2.框架
        spirngboot:  
            pom.xml 
            application.yml/application.properties(@PropertySource("classpath:/user.properties") @Value("${file.path}"))
        lombok:
            @Data @Access(chain=true)
        mybatis:  
            @MapperScan("com.jt.sys.dao") 为持久层接口产生代理对象
            代理对象:
                jdk动态代理: 必须有接口
                cglib动态代理: 有无接口都行, 代理对象时被代理者的子类
        mybatisPlus:
            以对象方式操作数据库
    3.前端
        ajax:
            局部刷新,异步请求(客户端,ajax引擎,后端服务器)
        跨域:
            同源策略: 请求协议://域名:端口号   应该都相同
            ajax请求网址 和 浏览器网址违反同源策略  
                浏览器网址:     http://localhost:8080/userList.html
                ajax请求网址:   http://localhost:8614/abc/a
                    协议不同 域名不同(映射的也不行) 端口不同
            解决: 跨域资源共享cros机制, 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
                    浏览器都支持改功能
                    后端服务器通过响应头信息添加允许访问的域名地址,后端UserController @CrossOrigin注解

# ssmpro2104本阶段学到的
    *动态为属性赋值
    springboot的开箱即用
    mybatis-plus
    StringUtils spring提供的字符串工具类
    spirngmvc流程
    @CrossOrigin
    md5加密,登录
    uuid秘钥,免登陆
    token session/cookie
    登录成功后跳转, 前端路由机制
    层级菜单, 层级列表
    mybatis分页查询
    mybatisPlus日期数据自动填充
    事务回滚
    全局异常处理
    商品分类列表查询, 一级二级三级, 使用map集合
    新增两个表, 主键自动回显
    文件上传
    nginx  反向代理,负载均衡 策略
    nginx图片回显(后端返回给用户url,回显时图片是url,使用nginx反向代理url到本地)
    hosts 本地域名关联
    tomcat集群 nginx配置 proxy_pass
    linux部署 tomcat集群,nginx(web)
# ssmpro2104本阶段学到的

笔记1

## 单体架构
### spirng boot, spring, mybatis

####   2021-03-03  ----------------------------
Chrome 的插件
IDEA  后端   无限试用版 
VSCode 用户界面

GC  垃圾回收

IDEA每一个Project都有自己的配置    maven 本地仓库  jdk

settings.xml
	本地库,远程库,jdk,
	
	
	

####   2021-03-04  ----------------------------
>>>>	回顾
	dosc.google.com
	石墨文档
	语雀
Chrome 插件
pdf chrome://flags
utf8 插件set character encoding
格式呈现JSON数据	jsonview

>>>>  -设置---------
settings.xml
	本地库,远程库,jdk,
	
	
	
IDEA设置
	maven		builder tools
	utf8			file Encoding
	包导入		
	jdk1.8		builder/compiler/java compilder
	keymap		
	代码提示		
	代码补全
IDEA项目
	empty project 相当于工作空间
	module 小写  package 小写cn.tedu
	rebuild
	清缓存	file/ invalidate caches/restart
项目配置
	project structure     jdk
>>>>	
	main 中的 args 参数 作用:  接收运行时的传入的数据,
	edit configurations	编辑配置  program arguments 接收

依赖 chrome 
https://mvnrepository.com/

项目结构
project structure ctrl+alt+shift+s

>>>>	Git全局配置  ***** ** *
		检查git配置
			git config --list
		配置git用户   全局用户配置
			git config --global user.name "赵庆"
			git config --global user.email "[email protected]"

idea 中 git操作
	配置git					version control中Git 找到此电脑已安装的git检测        plugins安装gitee插件
	登录						version control中gitee登录
	创建本地库 				vcs中create git repository 
	查看本地库				settings中的version control
	exclude文件配置		.git/info  
	add						项目右键 git add 然后commit  directory
	commit					提交到本地仓库
	history 怎么切换		查看历史版本
	share到远程仓库			分享到远程仓库   只执行一次
	push							每次本地修改后 add  commit push
	远程库 修改 创建文件	
	update 							更新本地仓库
	clone								克隆远程仓库
	克隆的项目配置 jdk maven utf8 
	maven项目添加到maven区				 pom.xml 文件上右键选择 add as maven project
	java项目										 src 转换为 sources   root 格式

exclude文件配置  .git/info  作用: 对上传的资源过滤,哪些提交,上传
			HELP.md
			target/
			out/
			### IntelliJ IDEA ###
			.idea
			*.iws
			*.iml
			*.ipr
			.gitignore
			### maven ###
			mvnw
			*.cmd
			.mvn/

####   2021-03-05  ----------------------------
# 系统公告
	业务描述
	系统原型设计 页面      
	
	数据库
	分层设计 
			http    tcp    

>>>>  数据库
	命令行
		set names utf8;  客户端编码
		status	数据库状态
		source 路径   导入数据库 执行.sql文件
		表  sys_notices
	
	idea连接数据库 
		name jt@localhost
		url:     jdbc:mysql://localhost:3306/jt?serverTimezone=GMT%2B8&characterEncoding=utf8mb4
		数据库操作
	
>>>>   spring boot  框架 脚手架
	
>>>>   创建
	spring initializr  spring初始化
	
	修改运行名
	
>>>>   spring boot 
	@SpringBootApplication springboot运行入口
	1.启动类  做了什么
		类:  交给spring管理 的类   不交给spring管理的类
		1).将磁盘中的类    读到内存 (位置, 技术--线程调用io读)
		2).类的信息的提取   构建对象  存储对象
		3).读取对象配置信息  对系统进行初始化配置
					扫描包,磁盘读取,线程io读取,读到内存,创建字节码对象.class,
						第一个加载的类?
	2.如何知道哪些类被加载到内存?
		jvm参数的配置  -XX:+TraceClassLoading         作用: 对类的加载过程进行呈现
			edit configurations ( run/debug configurations配置 )  
				environment环境 (vm  args directory variables  )  
	3.类文件读到内存后
		注解 描述数据的元数据 (类 参数)(数据对象)
		读取到容器中bean   
		多个bean存在map中
		BeanFactory反射实例   创建对象
		存到map可重复用的对象

1) 基于线程调用 i/o 从磁盘读取类,将其加载到内存,此时会基于类创建字节码对象(其类型为 Class 类型)
2) 基于 Class 对象(字节码对象)读取类的配置信息(例如类上有什么注解-例如@Component,属性上有什么注解,....)
3) 基于类的配置进行相应的配置存储 ( 交 给 spring 管理的类的配置 )-Map
4)  基 于 类 的 配 置 借 助 BeanFactory 创 建 类 的 实 例 ( 对 象 ), 多 个 对 象 存 储 到
Map


>>>>>>>>
	池化思想:享元模式
	提升系统性能    高效  低耗
>>>>   springboot   使用    hikariCP    连接数据库
>>  池
	01-javase
		IntegerTests.java
200不在integer -128到127内

>>  为什么使用连接池  
	频繁的数据库连接关闭影响性能     TCP协议 3次握手 4次挥手??????????????
	
>>  数据源规范
	javax.sql.DataSource 接口           不同团队创建不同连接池对象  耦合接口(规范)  方便切换不同商家   

>>  数据库连接池原理 构成
	??????????????

>>  hikariCP
	依赖 mysql data-jdbc
	04-notice-ssm  DataSourceTest    
	数据源


http://github.com/alibaba/nacos
liaochuntao
jdbc


>>>>  双重校验
	if(a==null){
		synchronized(this){
			if(a==null){}
		}
	}
保证安全提高并发
>>>>  时区
	GMT%2B8
	Asia/Shanghai
	
>>>> 注意:************
错误看 cause by

>?????????????????<
	utf8mb4
	idea调试 几个按钮
	运行错误not bean 如何解决?     依赖注入问题  导包 jdbc依赖添加 
>?????????????????<


####   2021-03-08  ----------------------------
## 回顾
>>>>  jdbc 访问数据库
	DataSource 对象  连接池
	
	熟悉jdbc  步骤     封装在具体的对象中
		获取连接
		创建Statement
		发生sql
		处理结果
		释放资源
		
	??	为什么使用 PreparedStatement 作用
		Statement不能识别?

>>>>  jdbcTests.java   testSelectNotices01()
	为什么使用list封装map?
		map是一行数据,用list存储多行
	
	元数据(标题 描述数据的数据) 数据

返回值在业务对象中,测试类中没有,       业务方法在main中
dao接口 dao实现类(包含jdbc) 
 
代码用活sql values
	封装  输入


@Repoditory
	标明这是一个数据访问对象


**-------jdbc-------**
> 1. 依赖:pom.xml
		mysql
		jdbc
> 2. 连接数据库配置:application.properties
		spring.datasource
			.url=jdbc:mysql://localhost:3306/jt?characterEncoding=utf8&serverTimezone=GMT%2B8
			.username = root  .password = root
> 3. 测试连接:DataSourceTests.java
		测试dataSource的连接对象: HikariDataSource
		
		测试类使用的注解:
			@SpringBootTest	修饰类		这是springboot的测试类
			@Autowried			修饰属性		自动装配,在ioc容器中查找并返回属性,
			@Test					修饰方法		测试类
> 4. JdbcTests.java
		获取数据源对象,连接数据库,对数据库进行操作
		
		jdbc步骤:
			建立连接
					conn = dataSource.getConnection()
			创建Statement/PreparedStatement
					stmt = conn.createStatement() /  conn.preparedStatement(sql)
			发送sql
					stmt.execute(sql);
			处理结果
			释放资源
					stmt.close();conn.close();
		
		testInsertNotices01()
			Statement创建 不需要动态传入SQL值
		testInsertNotices02()
			Preparedment创建  使用?动态输入  pstmt.setObject(index,x)
		testSelectNotices01()
			查询需要获取查询结果    对结果集处理 每一行放在map中,每个map放在list中 返回给用户   map.put()存储到map中
		testSelectNotice02()
				使用元数据获取字段名,,,不需要写很多个map.put()  只要循环元数据就行
> 5. 最终实现写在main里面
		使用接口实现类
		NoticeJdbcDao.java
		NoticeJdbcDaoImpl.java
		NoticeJdbcDaoTests.java
> 6. 用活
		把insert的sql语句和添加的值values作为参数传入程序
			测试时定义SQL语句 调用方法传参
			值values 使用object数组传入方法     实现类中foreach循环object数组获得值
*?*
自己创建的接口 使用时no bean  接口实现类的@Repository(标识这是一个数据访问对象的具体实现类)
**-------jdbc-------**


####   2021-03-09  -------------------------------------------------------------
SysNotice.java pojo
SysNoticeDao.java  interface
SysNoticeMapper.xml
NoticeDaoTests.java  test

>>>>  JdbcTemplate类
	模板 封装了jdbc编程步骤
	
>>>>  mybatis
	依赖, spring 框架启动时会对 mybatis 进行自动配置。SqlSessionFactory 工厂对象的创建。
官网: mybatis.org/spring    http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
	使用mybatis需要sqlsessionfactory和mapper interface
	
>>>>  业务实现
	接口 @Mapper 
	Dao data access object 数据访问对象
	两类对象 1.业务 2.存数据sysnotice
	
>> 04-notice-ssm
		pojo 对象    创建接口     .xml配置文件      test测试

*-*	pojo	SysNotice.java		pojo 对象私有属性 get set toString方法
*-*	dao	SysNoticeDao.java 数据持久层接口
					
				查询
				删除
				修改
				新增
*-*	mapper/sys	SysNoticeMapper.xml 
								文件头 官网:https://mybatis.org/mybatis-3/getting-started.html
				selectNotices


*-*	test	NoticeDaoTests.java
					springboot管理的类  有@Autowired  会在bean池中查找
					SysNoticeDao对象是     Proxy代理对象       a实现b a is a b的特殊   ( is  a )
					
					
					testSelectNotices()
						创建对象SysNotice,通过对象封装要写入到数据库的数据
						执行方法, 返回list    循环list输出
						

**--项目--**
01-javase  VarParamTest.java   可变参数
04-notice-ssm
	pojo	SysNotice.java		
	dao	SysNoticeDao.java
	mapper/sys	SysNoticeMapper.xml 
	test	NoticeDaoTests.java

	
####   2021-03-10  -----------------------------------------------
读取数据库内容,   写入数据库

is a     继承实现
has a   有一个   对象和它的成员的从属关系

>>>>   @Qualifier("sysNoticeDao")*表明了哪个实现类才是我们所需要的*
		@Autowired默认按照类型匹配注入bean,如果有多个实现类,搭配@Qualifier(“实现类名称”)表明注入的是哪一个实现类的bean
同时有多个同名的实现类 使用@Service修饰  有 @Service("a")  @Service("b")  @Service("c")
 @Autowried修饰的需要用到的属性使用@Qualifier("a") 标明使用a的实现类

日志 SLF4J
	日志级别  error > info > debug(调试信息)  >  trace(跟踪程序时)


>>>>  spring web
	过滤器 filterchain
处理流程:1) DNS

url设计 
	Rest风格
**-- 项目 --**
SysNoticeDaoImpl.java 自己写的实现类
SysNoticeServiceTest.java
LogTest.java
####   2021-03-11  ----------------------------
代理对象

>>	JsonTests.java
服务端 数据返回给 客户端   返回的转换为JSON字符串     转换为指定对象
	JSON字符串跨平台 {"key":vlaue,"key":value}    [{},{},{},{}]
	
>>>>  postman     测试服务
	get		查询
	post		新增
	put		更新
	delete	删除
>>>>  Spring Framework   资源整合框架
**https://spring.io/**
	IoC   控制反转
	AoP
	Web

>>>>  修改日期格式
	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss,timezone="GMT+8")  描述属性或get方法
	时间差8小时 转换时按照 格林威治 时间		timezone = "GMT+8"
>>>>  使用时间查询   2021-03-12 15:27:12   不能用 springmvc不能处理			2021/03/12 15:27:12
	@DataTimeFormat(pattern="yyyy-MM-dd HH:mm:ss)   描述属性或get方法

>>>>   CRUD
	create
	retyieve
	update
	delete
>>>>  controller
	@RestController
	@RestMapping("Contants.NOTICE_ROOT_PATH")

>>>>  异常处理规范
	springmvc中提供的



**--项目--**
JsonTests.java
SysNoticeController.java    添加控制层  使用url访问     用postman测试



400 客户端向服务端传递的参数 类型 格式 个数



####   2021-03-12  ----------------------------
>>>>  拦截器
	请求数据处理 预处理      响应数据加工
	方法 preHandler
>>>>   过滤器  Filters   

>>>>   分页插件          拦截器
	接口的底层代理实现类  通过sqlsession与数据库会话  过程中拦截  改变sql语句
	limit #{startIndex},#{pageSize}

>>>>   封装请求对象     工具类  获取方法参数的  util         获取请求对象中的参数信息

http://localhost/notice/?pageCurrent=1&pageSize=2

>>>> 注解括号中直接写值,是给注解的value属性赋值

**--项目--**
SpringwebConfig.java
TimeAccessInterceptor.java
MainTest.java
SysNoticeController.java中的查询拦截


ThreadTests.java Lamdba简化使用接口方法
ListTest.java 迭代list

ServletUtil.java
PageUtil.java
StringUtil.java
工具类  在业务层上提取 同性代码

####   2021-03-15  ----------------------------
# web
	1.初始思想
模块: controller -访问> service -访问> Dao -访问> database
请求url:
	Rest风格      ???????

请求方式:
	类@RequestMapping()
	方法    在postman中使用相同连接 不同的请求方式  执行的是不同的方法
			@GetMapping(处理 Get 请求,主要应用于查询)
			@PostMapping(处理 post 请求,主要应用于新增操作)
			@PutMapping(处理 put 请求,主要应用于更新操作)
			@DeleteMapping(处理 delete 请求,主要应用于删除操作)

请求方法参数类型    ?????????
	pojo 使用@RequestBody      application/json
	
	1) 直接量(8 中基本数据类型+String+Date+数组)
	2) Pojo 对象(必须提供 set 方法)
	3) Map 对象(必须使用@RequestParam 或@RequestBody 注解描述)

# 拦截器

# 插件  分页

#### 框架      封装了servlet对象   响应对象
# 看重性能   使用底层原始   servlet       javaEE规范
# javaEE三剑客   Filters  Servlet  listener监听
# Servlet接口 java中的       
# ctrl+H实现   继承体系
# servlet处理请求返回response

# tomcat/jetty web容器
实现规范DispatcherServlet.java   

servlet拿到请求  
	- request.setCharacterEncoding("utf-8")
	- String str = request.getParameter("pageCurrent")
	- Integer.parseInt(str)
	- service.doMethod()
	- response.setCharacterEncoding("utf-8")
	- reponse.setContentType("application/json")
	- PrintWriter pw = reponse.getWriter()
	- pw.wirte(content)
	- pw.flush()

mvc 是一种设计思想  实现规范


# 依赖  没有写版本
parent指定了 版本
scope什么时候有效
	annotationProdessor编译时有效


# 插件  Lombok
	作用:  简化代码 
	1.安装插件    2.启动注解处理    3.依赖    4.
	
	pojo中的方法    
		没有get方法 不能将对象转换为Json字符串
>>>>  LombokTests.java

>>>> 如何写一个Lombok
	编译原理

>>>> 注解
@JsonFormat() 底层创建get方法
Lombok
	pojo中
	@Setter  在编译时  会在.class文件中添加set方法
	@Getter  在编译时  会在.class文件中添加get方法
	@ToString 在编译时  会在.class文件中添加toString方法
	@NoArgsConstructor 无参构造
	@AllArgsConstructor 全参构造
	@Date
	@EqualsAndHashCode
	log impl中
	@Slf4j 会创建Logger log常量

# 热部署插件
>>>>  作用: 类在更改内容后    自动重启服务加载类(main resourdes ),不是所有的类(静态资源  test类 )
>  ClassLoader   类加载器
		.class文件   从磁盘/网络读到内存中
>>>>  过程?????

> 依赖 devtools

# 泛型 ArrayList   
	第一个E是泛型方法, 第二个E是泛型类型约束
	
	1)是编译时一种类型, 运行时无效
			用于约束类中 属性   方法参数类型   返回值类型
	类型擦除?在运行时泛型会变成Object
	
	2)应用场景: 框架-共性, 工具类-, 通用方法
			泛型方法减少检查
			
	3)类型: 类泛型, 方法泛型
			class ClassA{} 
			class ClassB{}
		类泛型: 主要约束类中 实例属性, 非静态方法参数, 非静态返回值类型
				 static class Contentr{
					 void add(E e){}
					 E add(){return null;}
				 }
		
			void method()
			   应用最多 静态方法 static void print(T t){}
					这是一个泛型方法 参数类型要写T  必须泛型是T(左边)
		方法泛型:<泛型>返回值类型<泛型>
		
	4)泛型限定通配符
		?	无界
		? super	有限  下届限定通配符   存数据时       使用Object
		? extends  继承  上届限定通配符  获取数据时   使用Integer Long
		
	5)用在哪里
		在collections.java
		
			
	01-javase   GenericTests01.java
						GenericTests02.java
					ListGenericTests01.java

>>>>  泛型编译时特性  反射运行时特性

# collections.java java中的集合工具类
	返回值类型左侧有泛型 就是泛型方法

# 序列化接口 Serializable 存数据


####   spring 资源整合框架
		框架底层提供的资源
		自己写的资源

######################### 遇到问题 先保留现场 what when where 
阿里/美团 日志  ?????
###  05-log-aop
## 数据库表
## 创建项目直接添加依赖
## pojo
## Dao
## SysLogMapper.xml
## Service
## Controller

# 依赖
	mysql
	spring-jdbc
	web
	mybatis
	pagehelper spring-boot
	spring-boot-devtools
	lombok
	
	spring-boot test
	spring-boot-maven-plugin
	junit

### AOP拿取用户日志    异步日志存储到数据库


####   2021-03-16  ----------------------------
# 项目
## 添加数据库数据
## 创建项目 添加依赖
## 配置application.properties
## mybatis层      1.pojo请求标准  2.dao接口  3.sql语句SysLogMapper.xml
## service层       1.接口   2.实现类   
## controller层   1.controller      2.接收resultset的pojo(JsonResult)响应标准
### web controller, jsonresult, exception, PageUtil, StringUtil, ServletUtil,    

# 条件语句
mybatis.org/mybatis-3/dynamc-sql.html
		Dynamic SQL动态sql
where-if
choose-when
####  高内聚低耦合 

# 项目依赖于项目

# 耦合于接口
	class SysLogServiceImpl 业务层实现类  耦合于数据层接口 SysLogDao


# AOP
如何在不修改源代码的基础上对对象功能进行拓展
1.继承: 强耦合
2.实现+耦合 组合
*--------*
A
B实现A 耦合A
扩展了C(注入A)
*--------*
>>> aop 设计思想      oop ioc mvc mvvm
	1.面向切面编程 是面向对象的补充和完善
	2.横向切面  功能的扩展/增强   @SLF4J/@Mapper
	
> 把扩展的业务写在切面中
> 广义封装
> 基于运行时动态


####   2021-03-17  ----------------------------
java基础,GC,多线程,数据库索引,jvm原理,jdk源码    
美团招聘job.meituan.com/job.alibaba.com

# AspectJ 框架  面向切面编程  -可以从字节码
添加依赖整合了aspectj
*注解 jdk1.5*
*耦合于接口调用实现类*
> 切面对象,为目标业务方法做功能增强
>> 1.创建注解, 应用于切入点表达式的定义
		RequiredLog.java
		给方法上加 扩展功能
	定义注解:
		@Target() 应用于哪里 方法,类,属性
		@Retention() 什么时期有限  编译时,运行时
	属性:
		String value() default "";  使用( @Retention(value="lvjing") )时给value赋值,可以不用写value,有默认值可以不用赋值  
		String operation();  @Retention(operation="lvjing")

>> 2.创建切面对象, 用于日志业务增强
		SysLogAspect.java
		@Aspect     切入点定义
		@Component  组件
		
		1.方法定义切入点   **切入点
			@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")      由RequiredLog注解描述的方法 为切入点方法
		2.切入点执行时执行的方法   **通知方法
			@Around("doLog()")  调用目标方法
		
	** 代理对象 业务层不写实现类底层框架产生代理对象  controller耦合代理对象
	** 切面为service层增强  具有切入点注解的方法进行增强
	** 使用日志 要在工厂中获取日志  @SLF4J
			
	** 切面对象的 返回值
		不加分页 
			return result; 有值
			return null;    无值
		加分页 切入点返回值有没有 都会返回控制端值
		-- 原因: 分页是mybatis层的 数据层  会在切入点之前执行 所以有结果

	** -- 基于aop代理   CGLIB代理    是实现类的子类(继承)   controller耦合service实现类
		 -- 基于组合代理 jdk代理            实现service接口
		++  底层代理类调用了 use a 切面
AI
Big Data
Cloud

>> 3.获取并记录详细日志       练习10遍
	1.获取用户行为日志 获取并赋值pojo
	2.封装用户行为日志 pojo封装
	3.打印到数据库

>>>>   步骤
> 1.RequiredLog.java    特点注解
		定义注解  定义一个属性获取operation     作用: 在方法上使用注解
		@Retention()  运行时期
		@Target()  可以用在哪里  类 方法 属性
> 2.SysLogAspect.java
		切面对象 作用: 日志业务增强
		@Aspect   此注解描述的类是切面类型, 封装 切入点 和 通知方法
				切入点       在特点注解描述的地方进行扩展业务
				通知方法    扩展的逻辑业务
		@Component   



####   2021-03-18  ----------------------------

>>> aop是什么  思想,

>>>   注解
	AnnotationTests.java
	获取类的注解的值
	获取类中属性的注解的值
>>> 
	classRelationTests.java
		is a     实现,继承
		has a  注入 private 
		use a  使用 类.属性(方法)
>>>  无限循环
	StackOverflowErrorTests
	

>>>>  通知类型
	@Around (优先级最高的通知,可以在目标方法执行之前,之后灵活进行业务拓展.) 
	@Before (目标方法执行之前调用) 
	@AfterReturning (目标方法正常结束时执行)
	@AfterThrowing (目标方法异常结束时执行) 
	@After (目标方法结束时执行,正常结束和异常结束它都会执行)
> RequiredTime.java
		定义注解 切入点方法
> SysTimeAspect.java
		通知类型的执行顺序
		@Around
		@Before
		@After
		@AfterReturning
		@AfterThrowing
		顺序: @Around(优先级最高) 本类其他before  其他切面before  目标方法  当前或其他切面的后续通知方法    //栈

>>>>   切面执行顺序
@Order(Ordered.HIGHEST_PRECEDENCE)
@Order(Integer.MIN_VALUE)

		@Order(1)
		@Aspect
		@Component
		public class SysTimeAspect {}
	@RequiredTime
	
		@Order(2)
		@Aspect
		@Component
		public class SysLogAspect {}
	@RequiredLog

>>>>  Spring AOP切入点表达式

>>>>  耗时    ??????
	查询时调用新增日志
	加了模拟耗时 时 第二个查询不能出结果
	查询时的线程   新增时的线程
	
	????       查询频繁的写日志  线程阻塞了
	&&&       异步记录日志
	下订单时   数据库  日志 卖家 库存  积分 .....  返回给用户结果
             
>>>>>  异步记录日志
 tomcat是个进程 有多个 线程   不用来执行耗时 存日志
 
 线程重用 -> 池化思想 -> 池中线程的重用 ->    线程池(自己建,框架的池)
 
 >>>>框架的线程池  在启动类中加@EnableAsync    ----启动时,初始化线程池
> 方法上加 @Async 描述的方法为一个异步切入点方法

>> 异步执行时 获得结果的时间  两个线程的执行顺序或者不在一个cpu  ThreadTests02.java

stackoverflow 网站

>>> 异步 返回结果 
public Future saveLog(SysLog sysLog) {
	return new AsyncResult<>(rows);    
}

>>>>>    Spring Thread Pool
 核心线程数  cpu核数*2+磁盘数    4*2+1
ThreadPoolExecuter  java提供的线程池
 java  tomcat  spring   都有线程池

线程池参数:?????


>>>>>    AtomicLong   递增对象    +atomicLong.getAndIncrement()

####   2021-03-19  ----------------------------
#   线程
> 线程工厂 new Thread(){@override run() }.start();  Runable中的run方法
>*自增 : AtomicLongTests.java
>*线程安全: CountTests.java
 cas算法  cpu自带的

docs.google.com

# 事务
    deleteById
		让已删除的数据回滚   @Transactional 单体架构可以
	spring中的事务控制 是通过aop进行控制的
>*SysLogServiceImpl.java 删除不成功回滚事务
@Transactional *业务层*描述的方法 事务切入点方法(功能增强 DataSourceTransactionManager.java   所有事物都是connection在控制)   可以加在类上
		doBegin()    doCommit()  代理对象 通过事务对目标对象的 目标方法进行功能增强
		在执行时先开启事务  ?谁来调用 -TransactionAspectSupport中的通知业务 进行功能增强
        *每层都会有事务 底层存在*
> @Transactional属性
* 所有的读写 都用true/false
readOnly=false    --就是增删改时不能读
timeout=60       --超过时时之后业务没结束就不等了
rollbackFor=RuntimeException.class  --运行时出异常回滚
isolation=Isolation.READ_COMMITTED 没有脏读

- 锁              ??????
	悲观锁:
- 多事务并发执行时 并发问题  ?? 脏读, 不可重复读, 幻读(统计)   -------修改事务的隔离级别
	脏读: 别的人读取了别人没有提交的事务 A(a1,a2,a3) B()  A执行a1没提交, B获取了a1,B的a1就是脏读   =隔离级别
			读别人已提交的
	不可重复读: A事务没结束,B把事务更新了       A读多次,每次一样,但出现了不一样就是不可重复读    =不让B更新 加锁
	幻读: A正在统计100, B删了10     A读到100 , 实际90    =给表加锁
	脏读 :: 一个事务中访问了另一个事务未提交的数据
	不可重复读 :: 一个事务查询同一条记录多次, 查到的结果不一样
	幻读 :: 一个事务查询两次得到的记录条数不一致

>  SysLogServiceImpl.java
		类 @Transactional(readOnly = false,
									timeout = 60,
									rollbackFor = Throwable.class,
									isolation = Isolation.READ_COMMITTED)
		findLogs   @Transactional(readOnly = true) 


# 代理对象
> 01-javase   JDKProxyTests.java
	项目中  :  Controller - Service接口 - Proxy - InvocationHandler - ServiceImpl - Dao
	jdk最重要的是 目标对象实现接口  实现兄弟类

## 权限管理子系统  动吧旅游
菜单: sys_menus
角色: sys_roles
用户: sys_users
  --  用户 n:n 角色 n:n 菜单
     ++  中间表: sys_ role_ menus   ,   sys_ user_ roles 
部门: sys_depts
  --  部门 1:n 用户   n进行维护(外键 )   逻辑维护在n这一方
日志:sys_logs
  --  用户 1:n 日志

> 权限框架 : shiro 用户深身份认证

> 先做 菜单表 

>>>>>     项目搭建
	父工程dbpms(pom)     dbpms-common    dbpms-admin
	公共  共性 特性

>>>>>    1:n
	role:  id name  user_id               user:  id username             user_role: id   user_id  role_id
			1             1								1                                           1      1            1
			2             1								2                                           2      1            2
			3             1								3                                           3      2            1
			1             2      这样不行

#    创建 maven ( 父工程不继承 )
	> 父工程 管理依赖   pom.xml  pom  pom工程
		-*-  06-dbpms 只有pom.xml文件  
					->- 06-dbpms-common   parent 06-dbpms   共性资源
					->- 06-dbpms-admin   依赖于06-dbpms-common   启动工程
>>>>  pom.xml
父工程:  06-dbpms 只有pom.xml文件  
	packaging-.-pom
	parent-.-spring-boot
	properties 指定依赖版本
	dependencies
	build  组件
通用工程:  06-dbpms-common   parent 06-dbpms
业务工程:  06-dbpms-admin   依赖于06-dbpms-common
	依赖于common  dependency-.-06-dbpms-common
>>>>>>>>>
> 启动工程 在admin
> application.yml   server datasource mybatis log

>>>>    通用内容设计     对象 


####   2021-03-22  ----------------------------
# 通用Module设计
> 领域对象 pojo
> 注解对象
> 异常类
> 工具类
> 请求处理
# 业务实现   写在admin中
## 菜单
> 业务
	各种管理 , 管理内部的操作  
	菜单的展示  一级目录 二级目录 三级目录
	对菜单的操作 查询所有,查询树结构,根据id查询,新增,修改
> 表

### 数据层
> 领域对象 pojo对象
	在三个层都有用到,  用来传递,接收数据 (接收客户端传递的数据参数, 数据库读到程序中 -返回给客户端)
* 对象 -对应数据库字段
* 序列化 和 反序列化
		序列化:指把java对象转换为字节序列的过程, 便于在网络传输或保存在本地文件
		反序列化: 指把字节序列恢复成java对象的过程,
* 实现Serializable接口   * 添加serialVersionUID      *存储数据的对象都实现此接口*
		在序列化与反序列化过程中会产生*各自的serialVersionUID*   为了序列化与反序列化相同的内容
		实现接口 为序列化与反序列化过程做标记,, serialVersionUID作为版本标识  反序列化时,相同则进行
> Dao逻辑
* 业务(方法)
> 映射 .xml
	join 和 left join??
		join 两个表中条件成立的数据       * 一级目录没有父目录但也要显示(显示所有内容, parentId只显示有的 使用left join)
	查询所有级别目录  c.parentId=p.id
### 业务层
> 接口
	方法
> 实现
* @Service
* @Autowired  注入dao接口
* @Transactional   事务处理
		- readOnly=false 增删改不能读
		- rollbackFor=RuntimeException.class  --运行时出异常回滚
		- isolation=Isolation.READ_COMMITTED 没有脏读
### controller
* Controller
		@RestController
		@RequestMapping("/menu/")
* 请求 post delete get put
* 参数 @RequestBody @PathVariable
* 响应   共性  JsonResult.java state message data	
* 异常 3种   全局异常共性 GlobalExceptionHandler.java @RestControllerAdvice  @ExceptionHandler(RuntimeException.class)

## 部门 Dept
> SysDept.java
> SysDeptDao.java
> SysDeptMapper.xml
> SysDeptService.java
> SysDeptServiceImpl.java
> SysDeptControllre.java
  
ctrl+f12 看方法

####   2021-03-23  ----------------------------
# json序列化和反序列化
	一种广义的序列化和反序列化
json序列化: 对象转换为json字符串
json反序列化: json字符串转换为pojo对象
	wwwwh when(何时,什么业务),what(什么错误),where(错误出在哪里cause by),why(为什么错,程序可能错的在哪里),how(如何解决)
	序列化失败: 在转换时, 类型不匹配, 时间Date

@Async SysLogServiceImpl.java  ??????
	@Async注解描述的方法为一个异步切入点方法,这个方法执行时底层会在新的线程中进行调用
	@Async注解描述的方法其返回值类型建议为void,假如为非void你需要对方法返回值类型进行设计,比方说方法声明为Future,方法内部的返回值为 return new AsyncResult(rows)
		 
## 角色
> 表 角色:菜单 n:n   需要中间表
> 难点, 添加()修改(权限菜单的展示(已经有的需要查出来)menuIds )

### Dao
* SysRole.java SysRoleDao.java CheckBox.java(存储)      SysRoleMapper.xml
* SysRoleMenuDao.java SysRoleMenuMapper.xml

>>SysRoleMapper.xml
* 查询(* name)
* 查询(id 以及管理的菜单id)
* 新增
* 更新
>>SysRoleMenuMapper.xml

### Service
* SysRoleService.java
	> 各个方法的业务
* SysRoleServiceImpl.java

### controller
	pageCurrent 第几页
	pageSize 一页中最多有多少数据
* SysRoleController.java
		分页 PageUtil.java 需要获取 Request 过程提取到 ServletUtil.java
			提取共性				需要判断 分页的参数是不是空, 提取到StringUtil.java
	把分页放在JsonResult.java中 controller中执行方法更简便



####   2021-03-24  ----------------------------
## 用户
### MD5密码加密算法
		MD5Tests.java
### Dao
> pojo
> User interface
> UserRole interface
> User .xml
> UserRole .xml
> service
> serviceImpl
> controller
笔记都在idea里面

RequestBody只能使用一个   描述一个参数
@PathVariable可以使用多个  描述多个参数



####   2021-03-25  ----------------------------
n:n 的关系维护方在 中间表
1:n 的关系维护方在 n表中
> 角色业务: 添加角色自身信息 -执行方法添加到数据库, 菜单授权 -添加角色菜单关系数据(先删除原有的关系,再添加新的关系数据)
> 查询用户 -用户自身信息, 用户角色信息, 菜单信息



#-------------------------------------#
* 1. 判断 要添加的角色是否存在 
		添加的是role_id 
			根据id查询返回结果来 判断
			
* 2. 查询用户 信息  角色  管理的菜单  部门
	select sr.name '角色',sm.name '菜单',u.username '姓名',u.email '邮箱',u.mobile '电话',sd.name '部门'
	from sys_users u
		left join sys_user_roles sur on u.id = sur.user_id
		left join sys_roles sr on sur.role_id = sr.id
		left join sys_role_menus srm on sr.id = srm.role_id
		left join sys_menus sm on srm.menu_id = sm.id
		left join sys_depts sd on u.deptId = sd.id
	where username = 'laohu';

	/*
		根据姓名
		查询用户信息 放在users中 姓名
		查询角色信息 放在roles中 据role_id - 查角色id放在 user_roles 据user_id - 查用户id放在 users中 据姓名
		查询菜单信息 放在menus中 据role_id
		查询部门信息 放在depts中 据user_id

		.xml文件 dao接口 业务层接口 实现类
		user业务层把 各个部分整合在一起
		最终在user控制层 使用业务从层方法
	*/
   
* 3. 查询权限
		select distinct permission
			from sys_user_roles ur
				join sys_role_menus rm
				join sys_menus m
					on ur.role_id=rm.role_id and rm.menu_id=m.id
			where ur.user_id=1
			 and trim(m.permission)!='' 
			 and m.permission is not null
#-------------------------------------#

# shiro 权限控制框架       *shiro.apache.org*    [](http://shiro.apache.org/reference.html)
> shiro框架 添加依赖 需要写 Realms 其作用: 访问数据库    > 其他文件需要配置  
> 两条线:  框架作用是: 用户的权限 认证和授权
*      认证: subject -> Security Manager -> Authenticator -> Realms
*      授权: subject -> Security manager -> Authorzer -> Realms
		subject , 主题
		Security Manager , 安全管理
			Authenticator , 认证者
			Authorzer , 授权
			Pluggable Readlms , 可插入领域
			Session Manager , 会话管理
			Session DAO , 会话数据
			Cache Manager , 缓存管理
		Cryptography 密码学
		
### 依赖
> 普通项目    shiro-spring
> springboot项目    shiro-spring-boot-web-starter需要Realm  创建Realm类

### Realm类
	ShiroRealm.java 类   extends /*AuthenticatingRealm*/ AuthorizingRealm   认证  授权
	在启动类中添加 Realm 对象配置

### 过滤规则
	哪些访问路径url 访问时 进行认证访问

### 在 spring 的配置文件(application.yml)中,添加登录页面的配置
shiro: loginUrl: /login.html
权限   指定访问url跳转到指定页面

## 认证
* 1. subject 把信息提交给 .login()方法     2.Security Manager  .login()方法
* 3. 把信息提交给一个方法 调用方法Authenticator  继承 Security Manager    4.他有认证策略
* 5. realms 从数据库中提取信息  进行比较
* 
* 底层Shiro框架的授权流程:
* 控制层  调用   subject 的子类 调用 .login() 方法  提交给 SecurityManager
* SecurityManager将认证操作委托给认证对象Authenticator
* Authenticator将用户输入的信息传递给Realm
* Realm访问数据库 并封装返回
* Authenticator对返回的信息进行身份认证

> 基于用户名查询    还没有传密码
> UsernamePasswordToken 令牌
######  笔记在idea中

> 三个对象 subject SecurityManager Realm
> 一张网 认证流程  subject -> Security Manager -> Authenticator -> Realms -> Database   认证在Authenticator
> 两个token  subject中的 realm查数据时
> shiro框架  我们需要做的提数据和查数据

## 断点看Shiro框架的过程 token

# Cookie Session
> Cookie
* 如何记录客户端的用户信息   username=lvjing    请求页面时cookie会被添加到请求中
> Session
* 
> 区别:
* Session是记录在服务端的,而Cookie是记录在客户端的。
## 登录成功后, 登录成功后的状态

## 登录成功之后就可以访问了
	服务器可以拿到 用户登录之后的会话状态


####   2021-03-25  ----------------------------
# 异常 没有的异常登录时给出提示
> 全局异常处理
* 打印日志 
* 给出用户反馈  设置JsonResult的值  setState(0)  
						判断什么异常 e instanceof XxxException 给出相应反馈setMessage("错误提示")
> instanceof 模式匹配
* if(e instanceof Exception){}  如果e是这个类型的就抛出指定异常
* 类型为引用类型的表达式可以使用instanceof进行测试,以找出表达式的运行时值引用的对象类是否可以转换为其他引用类型
* if(object instanceof String){String a = (String)object}

# 登录之后,关闭浏览器,再次就不用登录信息存在哪里
Client客户端      
Web Server服务端

HTTP无状态协议

> 登录会生成值Cookie
	服务器端创建user 创建Session(id)会话   生成Cookie对象存储Session地址(JSESSIONID)返回给客户端   客户端存储在浏览器中
	客户端再次发起请求 会携带JSESSIONID 访问服务器  服务器 据JSESSIONID -> get session id -> session ->user
* Cookie存储在浏览器 服务端生成      周期:1.会话C 浏览器关闭后就结束  2.持久C 设置C周期                          类似于员工卡 会员机制
* Session存储在服务端 服务端生成     周期30分钟

# 授权
* 1. shiro框架执行Dao层方法获取数据库中请求用户的权限    -数据层 定义方法 在数据库查询用户对菜单的权限 
* 2. shiro框架查找@RequiresPermissions("sys:user:update")  注解并获取注解中的权限标识
* 3. 获取的权限标识 与 数据库中的菜单权限进行比较    
* 
* 底层Shiro框架的授权流程:
* Subject 调用方法checkPermission把用户需要的权限提交给 SecurityManager 

   信息来自哪里
> @RequiresPermissions("sys:user:update")  授权切入点方法  shiro框架提供
			告诉系统 此方法需要权限

> 有些方法需要授权 有些不需要   AOP  -- 对判断用户有没有权限的动作封装  
	-> 底层查询到了所有的权限信息 判断请求是否包含在数据库查到内容里
* 授权逻辑   Shiro框架底层封装在AOP中的通知方法
* controller -> AopProxy -> AuthorizingMehtodInterceptor 
			-> subject.checkPermisssion -> SecurityManager -> Authorize -> Realm

> 查询时添加权限, 执行查询到的结果是, 登录用户的权限信息????
* 执行方法时, 两个查询, 1.注解的权限查询 封装在PageHelper中了  2.查询用户信息,没有封装到分页
+ 			解决1.: 把分页放在service实现类中执行,权限之后执行分页     业务层接口实现类控制层执行方法 改动大
+ 			解决2.: 权限放在controller控制, 注解方法控制端      
+ 						controller层在产生代理对象时 会把url的注解扔掉 --使用DefaultAdvisorAutoProxyCreator对象指定代理类的创建
* ++++整合的资源很多,有问题 Shiro PageHelper????      * ShiroDefaultAdvisorAutoProxyCreator
   在写业务层时  查询users返回值直接使用pageinfo 那权限注解就可以直接写在业务层,不需要很大改动

>>>>>  获取登录用户
* String modifiedUser = ((SysUser)SecurityUtils.getSubject().getPrincipal()).getUsername();

# 进阶    配置写在启动类中
> session配置
* SessionManager

> 记住我
* 登录之前对token配置RememberMe   --token.setRememberMe(true);
* 写自己的cookie保存时间 7天

> ???   重启服务后,再次直接访问user会让登录
* 原因: 重启的服务不能对原有的cookie解密, 并不是原有的cookie不管用
* 设置指定的key值, 每次cookie的解析都一样
* cManager.setCipherKey(Base64.decode("WGjHie9R114WBoCm3TAZ0g=="));

> 授权缓存配置
* 置 Shiro 中自带的 CacheManager 对象,此对象可以通过 Cache 缓存授权时获取到权限信息,下次再访问授权方法时不需要再查用户权限,

> @Bean 
* 这个注解主要用在方法上,声明当前方法体中包含了最终产生 bean 实例的逻辑,方法的返回值是一个 Bean。这个 bean 会被 Spring 加入到容器中进行管理,默认情况下 bean 的命名就是使用了 bean 注解的方法名。@Bean 一般和 @Component 或者 @Configuration 一起使用。
*  @Bean(name = {"myUser", "yourUser"})
    public User user() {
        return new User;
    }

> 修改密码=
* 



####   2021-03-29  ----------------------------
# 04-notice-ss   公告业务系统   页面实现    添加,删除,修改
## 单体 前后端分离 
## 1. 2. 3. 4. 5.页面架构 6.代码实现
* html呈现数据/css渲染数据/javascript动态效果/ 三剑客
* jquery/bootstrap(内置了html css js )  框架
* SPA (单页应用设计  single page web application)  :框架 一个body 多个div    -- 提高客户端与服务端通讯效率

## 列表数据加载 呈现
> 通过ajax中的url请求服务端, 获取result(JsonResult)
> 对result进行处理 展示在页面中
jquery
ajax
循环 迭代数据呈现
tBody.empty() 清空
records.forEach() 迭代
tBody.append()在被选元素的结尾插入指定内容


*  ???
> 1
跨端     : 就是平台 手机端, PC端
跨域     : 当一个请求url的协议(protocol)、域名(host)、端口(port)三者之间任意一个 与当前页面url不同即为跨域
				同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互
响应式  : 一个网站能兼容对个终端    通过各种尺寸的设备浏览网站获得良好的视觉效果的方法
> 2
request   请求
result      结果
response 响应
> 3
localStorage 浏览器本地存储name/value对 相当于Map
	localStorage的存储,读取,删除
		window.localStorage.setItem('key',value)   window.localStorage.setItem('key',JSON.stringiFy(object))把object转换为JSON字符串传入
		window.localStorage.getItem('key')            JSON.parse(window.localStorage.getItem('key'))把字符串转换为对象
		window.localStorage.removeItem('key')
		window.localStorage.clear()
> 4
button与input type="button" 的区别
在 button 元素内部,可以放置文本或图像。这是< button>与使用 input 元素创建的按钮的不同之处。
 < button> 控件提供了更为强大的功能和更丰富的内容
> 5
* 1. vue 已经3.0 (相比2.0大小减少50% 性能提高40%)
		element-ui 使用 vue2.0
* 2. bootstrap3 稳定      getbootstrap.com 5.0   bootcss.com 3

# notice-jquery.html 页面实现
## 页面布局
> 标题
> 内容
> 内容列表
* 使用表格形式
* 标题thead为静态, 内容tbody使用jquery从服务端获取(初始内容为 数据正在加载中...colspan横向合并表格 )
> 分页(上一页,下一页)
* 上一页,当前页/所有页,下一页,输入页码,跳转
* 按钮给class值, 在实现按钮功能时获取按钮
> 代码编辑
## 查询内容呈现
> 通过ajax获取result   把获取的结果呈现在页面tbody中   ajax设置url success方法(如果服务端没有抛异常执行*1. 函数doHandleQureyResponseResult* 打印在页面)
> 服务端抛出异常,服务端捕获异常,     没有异常state=1,处理正确结果,执行*1.1 函数doHandleQueryOk*     捕获异常state=0执行*1.2 函数doHandleQueryError*
> 处理正常查询结果 把结果给tbody*1.1.1 函数doSetTableBodyRows*    分页查询*1.1.2函数doSetPagination*
> 设置tbody中的值, 获取tbody对象,清空原有内容,    迭代结果,获取每条(行)记录,把每行放在tbody后(方法append()  参数为每行记录中的每个元素) *1.1.1.0函数doCreateRow*
> 获取每行记录中的元素值 


>处理异常查询结果
## 分页
> 添加点击事件
> 注册分页事件 $(".pagination").on("click",".pre,.next,.jump",doJumpToPage);
> 设置分页信息*1.1.2.0 函数doSetPagination*  --获取结果中的页码数和每页条数   --设置显示页数 1/3  --把页面数存在本地存储localStorage中set
> 执行点击事件函数   --获取class属性值  --获取当前页面值 current size  --ifelse 执行按钮点击 修改页码 pre next jump    --jump 获取输入的值  $("form input[name=pageCurrent]").val()
> 基于新的页码查询

> 问题
* 点击上(下)一页  不能超出范围
* 跳转没有的页面给提示
* 跳转结束后,清空输入框中的内容
* 把在输入框,localStorage中获取的值强转为int类型进行比较
* 跳转指定页面  f5刷新显示第一页

## 页面加载完成执行查询
> 页面加载函数
* 执行查询
* 注册分页

####   2021-03-30  ----------------------------
?    result.data 中的数据哪来的  pages pageNum
?    params
?    ajax请求的属性什么意思
?    监听
*    模板字符串 console.log(`a1的值是${a1} 反引号)
*    反引号 模板字符串

> 获取页面参数值
$("#typeId").val();
$("#noticeEditForm input:redio:checked").val();

## 根据标题查询


## 删除

## 添加

## 修改

## 刷新

## 小知识点

* 刷新
* 



####   2021-03-31  ----------------------------
# notice-vue
## vue/Axios/BootStrap
> Vue    ????
> Axios  ????
> Dom树 node节点 document object model 文档对象模型 (.html .xml) 在文档加载到内存中形成dom树
> js核心 EcmaScript
> Bom 浏览器对象 window
> th td th用在thead中 td用在tbody中 
> let块作用域(方法内部)  var
# vue 渐进式框架  就是使用什么就加入什么
> npm(node.js)  nose包管理
> 添加vue.js 和 axios.min.js

### 展示数据
### 分页
### 查询





###
vue获取按钮中的id
谷歌快捷键设置





####   2021-04-01  ----------------------------
# vue组件化   router

# 跨域访问  (3种)
服务端 80
客户端 9000
> 1. controller层 @CrossOrigin描述类   缺点,1.没有这个类 2.进行了认证,执行中到不了controller
> 2. 基于WebMVCConfigurer接口重写addCorsMappings()方法  仅仅跨域的配置, 过滤器,优先级都没有
> 3. 配置类中 ,  通过FilterRegistrationBean对象进行过滤器
> 基于过滤器的配置
* 把优先级设置高一些

> 前后端分离 前端后端不同的服务(url, 端口)  就有了跨域Cors
* ajax 异步加载,局部刷新


> 客户端跨域
* 跨域代理Proxy
# 06-dbpms-ui
modules
index.html
login.html

cookies

你可能感兴趣的:(note)