zoukankan      html  css  js  c++  java
  • Java学习总结

    目录

    一、 重要图详解: 2

    (一) 1DispatcherServlet 2

    (二) 2ssm框架简图 3

    (三) 3spring容器 4

    (四) 4、客户端和服务端关系 5

    (五) 5spring容器创建实例的两种方式 6

    (六) 6、系统架构分层 6

    (七) 7IOCDIDL 7

    (八) 8、乱码问题 8

    (九) 9Cache缓存 9

    (十) 10Shiro-Aop实现权限认证流程 12

    (十一) 11、项目流程图 13

    (十二) 12Tomcat工作图 14

    (十三) 13JVM(1) 15

    (十四) 14JVM(2) 15

    (十五) 15、高手班内容: 17

    (十六) 单点登录业务实现 17

    二、 框架基础知识 19

    (一) 前端知识 19

    (二) MapPOJO封装数据库数据 20

    (三) AOP相关知识 20

    (四) Java实体类(entity) 20

    (五) js端解决问题方法: 21

    (六) SpringBoot快捷键: 21

    (七) CMD命令: 21

    (八) Nginx命令: 22

    (九) 重要网站 22

    (十) Springboot注解整理 23

    (十一) Springboot项目启动后,spring容器怎么启动。 24

    (十二) 静态代码块: 25

    (十三) Java中的变量分类: 25

    (十四) JVM调优: 25

    (十五) Java四大引用: 27

    (十六) SpringBoot 29

    (十七) Nginx基础命令 31

    (十八) Redis基础命令 31

    (十九) 几种常用AOP代码示例: 31

    1、捕捉业务层异常的切面 32

    2、 运行时间的切面 33

    (二十) @Controller@RestController的区别? 35

    (二十一) Linux系统防火墙 35

    三、 手残导致的单词错误问题: 35

    四、 代码总结: 37

    (一) 页面控制层的返回页面的优化方法: 38

    (二) 用户名数据库校验: 38

    (三) Insert时用到useGeneratedKeys="true" 40

    (四) 方案1:数据层嵌套查询 --> 41

    (五) 方案2:数据层多表查询 --> 42

    (六) association 43

    五、 动吧项目逻辑图分析: 44

    (一) 菜单项CRUD 44

    (二) 角色项CRUD 46

    六、 Bug 51

    七、 Springboot项目搭环境怎么搭: 51

    一、重要图详解:

    (一)1DispatcherServlet

     

    1、浏览器输入网址,发送url请求,经过过滤器处理后,发送到前端控制器(DispatcherServlet),收到请求后通过url地址调用处理器映射器(HandlerMapping)相当于注册中心,里面包括目标对象和目标方法。Url 、controller方法名。 

    2、处理器映射器找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller名返回给前端控制器;

    3、前端控制器把controller方法发送到处理器适配器,由它找到合适的handler处理器进行业务处理

    4、handler处理器里包含控制层,业务层,dao层。Controller调用业务逻辑处理后返回ModelAndView到前端控制器,然后前端控制器调用视图解析器viewResolver进行解析,为View添加前缀后缀,并将结果再返回给前端控制器

    5、前端控制器根据Model(数据)View进行渲染(/templates/pages/goods.html)响应到客户端.

    HandlerMapping里面的key相当于url,@RequestMapping(url);

    HandlerAdaptor[əˈdæptər]找到合适的处理器(handler)处理业务逻辑,大概有9个处理器
    3Mybatismybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。

    (二)2ssm框架简图

     

    (三)3spring容器

     

    springboot工具创建springboot maven项目后,自动生成一个启动类Application.class,启动类上的@SpringBootApplication 注解修饰或描述启动类,用于告诉底层系统,

     * 1)读取spring-boot-autoconfigure.jar包中的spring.factories

     * 2)对此启动类以及所在包以及子包的类进行扫描,检测此类是否是spring管理的对象

    ApplicationContext是一个接口,继承BeanFactory,给工厂创建的对象选择不同作用域的map进行储存

     

    (四)4、客户端和服务端关系

     

    (五)5spring容器创建实例的两种方式

     

    (六)6、系统架构分层

     

    (七)7IOCDIDL

     

     (八)8、乱码问题

     

    Get请求乱码

     

    数据库连接方式乱码

     

    (九)9Cache缓存

     

    readOnly=false;从缓存中拿数据是反序列化过去,创造一个新对象,地址变了,obj1!=obj2;如果改了obj1,缓存中不会变化,这样obje2不会改变,数据安全性得到保障。Mybtis系统默认是false,因为安全;

    readOnly=true;从缓存中是引用对象,地址不变,obj1=obj2;这样效率高,但是如果改了obj1,缓存中会变化,这样obje2也会跟着改变,数据不安全。

     

    一级缓存

    一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。

    一级缓存的工作原理

     

    用户发起查询请求,查找某条数据,sqlSession先去缓存中查找,是否有该数据,如果有,读取;

    如果没有,从数据库中查询,并将查询到的数据放入一级缓存区域,供下次查找使用。

    sqlSession执行commit,即增删改操作时会清空缓存。这么做的目的是避免脏读。

    如果commit不清空缓存,会有以下场景:A查询了某商品库存为10件,并将10件库存的数据存入缓存中,之后被客户买走了10件,数据被delete了,但是下次查询这件商品时,并不从数据库中查询,而是从缓存中查询,就会出现错误。

    既然有了一级缓存,那么为什么要提供二级缓存呢?

    二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。二级缓存的作用范围更大。

    还有一个原因,实际开发中,MyBatis通常和Spring进行整合开发。Spring将事务放到Service中管理,对于每一个service中的sqlsession是不同的,这是通过mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer创建sqlsession自动注入到service中的。 每次查询之后都要进行关闭sqlSession,关闭之后数据被清空。所以spring整合之后,如果没有事务,一级缓存是没有意义的。

    二级缓存

    二级缓存原理:

     

    二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

    UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中

    (十)10Shiro-Aop实现权限认证流程

    AnnotationAwareAspectJAutoProxyCreatorspringboot框架的代理对象,通过AopUtilsscan(扫描)AdvisorAdvisorspring框架里的接口AuthorizationAttributeSourceAdvisorshiro框架里面顾问类,实现了Advisor接口;通过matches方法判断目标类和方法是否有注解,有注解返回true,通过Advice(通知)进行功能加强

     

    (十一)11、项目流程图

     

    (十二)12Tomcat工作图

     

    Protocol:网络数据交换规则,例如HTTP协议

    Port:端口

    Parse:分析

    (十三)13JVM(1)

     

    Java的三大虚拟机是HotSpot,JRockit,J9HotSpot虚拟机包括Server版和Client版。虚拟机装在操作系统(OS)上,OS调用JVM交给CPU执行。

    (十四)14JVM(2)

     

    .class文件经过类加载器加载。


    (十六)单点登录业务实现

    业务说明:用户信息一定不能保存到session,由于(多台服务器)Session不能共享,所以无法实现单点登录.

     

    单点登录实现步骤

    一、用户输入用户名和密码之后点击登录按钮发起url请求.

    url: "/user/doLogin?r=" + Math.random(),

    二、JT-WEB服务器接收用户的参数username/password(明文),将参数发给jt-sso(消费者)系统实现业务处理.

    WEB项目的Controller层(Dubbo消费者)

    @RequestMapping("/doLogin")
    
    @ResponseBody
    
    public SysResult doLogin(User user,HttpServletResponse response,HttpServletRequest request) {
    
    //获取userIP
    
    String userIP = IPUtil.getIpAddr(request);
    
    String ticket = userService.findUserByUP(user,userIP);
    
     
    
    //判断数据是否为null
    
    if(StringUtils.isEmpty(ticket)) {
    
     
    
    return SysResult.fail();
    
    }
    
    //将ticket信息保存到cookie中
    
    Cookie cookie = new Cookie("JT_TICKET", ticket);
    
    cookie.setMaxAge(7*24*3600); //7天有效
    
    cookie.setPath("/");         //cookie数据读取的范围
    
    cookie.setDomain("jt.com");  //设定cookie的共享
    
    response.addCookie(cookie);
    
    //将username信息保存到cookie中
    
    Cookie cookieUser = new Cookie("JT_USER",user.getUsername());
    
    cookieUser.setMaxAge(7*24*3600);//7天有效
    
     cookieUser.setPath("/");    //cookie数据读取的范围
    
    cookieUser.setDomain("jt.com");  //设定cookie的共享
    
    response.addCookie(cookieUser);
    
    return SysResult.success(); //正确返回
    
    }
    

      

     

    三、JT-SSO系统RPC接收数据之后,链接数据库,实现数据的校验

    四、如果根据username和password查询到用户的数据.则开始单点登录的流程.

    1)动态生成密钥,要求用户唯一.

    2)user对象转化为JSON数据,利用hash数据结构保存用户信息

    3)保存数据时,控制数据的有效时间. 设定超时时间7天有效.

    SSO项目的ServiceImpl层(Dubbo生产者)

    /**
    
     * 1.根据username和password(明文~~密码)查询数据库.
    
     * 2.为null return null   
    
     * 3.不为null, 准备ticket数据 UUID 准备userJSON数据
    
     *  将数据保存到redis中. 7天有效.
    
     * 4.返回秘钥.
    
     */
    
    @Override
    
    public String findUserByUP(User user,String userIP) {
    
    String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
    
    user.setPassword(password); //密码加密
    
    //根据对象中不为null的属性充当where条件 关系符=号
    
    QueryWrapper<User> queryWrapper =
    
    new QueryWrapper<User>(user);
    
    //根据条件查询数据库记录
    
    User userDB = userMapper.selectOne(queryWrapper);
    
     
    
    //判断userDB是否为null
    
    if(userDB == null) {
    
    //用户名和密码不正确
    
    return null;
    
    }
    
     
    
           /**
    
     * 为了保证redis资源不浪费,则需要校验数据
    
     * 如果检查发现当前用户已经登录过,则删除之前的数据
    
     */
    
    if(jedisCluster.exists("JT_USER_"+user.getUsername())) {
    
    //之前登录过,删除之前的ticket
    
    String oldTicket = jedisCluster.get("JT_USER_"+user.getUsername());
    
    jedisCluster.del(oldTicket);
    
    }
    
     
    
     
    
     
    
    //程序执行到这里说明用户输入正确.
    
    //3.1获取uuid
    
    String ticket = UUID.randomUUID().toString();
    
    //3.2准备userJSON数据  数据必须进行脱敏处理
    
    userDB.setPassword("123456");
    
    String userJSON = ObjectMapperUtil.toJSON(userDB);
    
    jedisCluster.hset(ticket, "JT_USER", userJSON);
    
           jedisCluster.hset(ticket, "JT_USER_IP", userIP);
    
    jedisCluster.expire(ticket, 7*24*3600);
    
     
    
           //将用户名与ticket信息绑定(防止用户重复登录)
    
    jedisCluster.setex("JT_USER_"+user.getUsername(),7*24*3600,ticket);
    
    return ticket;
    
    }
    

       

    五、.JT-SSO.将请求处理之后,返回ticket数据给jt-web服务器.

    .将数据通过客户端Cookie保存起来,设定过期时间.设置Cookie数据共享

    七.当用户再次访问时,jt-web服务器根据ticket信息查询redis服务器.如果数据存在则回显数据,如果数据不存在则要求用户再次登录.

    重点:用户数据回显,需要网页有cookie数据

     

    var TT = JT = {
    
    checkLogin : function(){
    
    var _ticket = $.cookie("JT_TICKET");
    
    //2.获取username信息
    
    var _username = $.cookie("JT_USER");
    
    if(!_ticket || !_username){
    
    return ;
    
    }
    
    //当dataType类型为jsonp时,jQuery就会自动在请求链接上增加一个callback的参数
    
    $.ajax({
    
    url : "http://sso.jt.com/user/query/"+ _ticket +"/" + _username,
    
    dataType : "jsonp",
    
    type : "GET",
    
    success : function(data){
    
    if(data.status == 200){
    
    //把json串转化为js对象
    
    var _data = JSON.parse(data.data);
    
    var html =_data.username+",欢迎来到京淘!<a href="http://www.jt.com/user/logout.html" class="link-logout">[退出]</a>";
    
    $("#loginbar").html(html);
    
    }
    
    }
    
    });
    
    }
    
    }
    
     
    

      

    URL地址

    http://sso.jt.com/user/query/15035732a39ae1dcfdcdbbd647089c3e?callback=jsonp1574039672842&_=1574039672914

    SSO项目的控制层UserControllerDubbo生产者)

    @RequestMapping("/query/{ticket}/{username}")
    
    public JSONPObject findUserByTicket(@PathVariable String ticket,
    
    @PathVariable String username,
    
    HttpServletRequest request,
    
    HttpServletResponse response,
    
    String callback) {
    
    JSONPObject object = null;
    
    //校验ticket是否有效,从redis中获取最终的ticket完成校验
    
    String redisTicket = jedisCluster.get("JT_USER_"+username);
    
    if(StringUtils.isEmpty(redisTicket)){
    
    object = new JSONPObject(callback,SysResult.fail());
    
    CookieUtil.deleteCookie("JT_TICKET","/","jt.com", response);
    
    CookieUtil.deleteCookie("JT_USER","/","jt.com", response);
    
    return object;
    
    }
    
    //判断redisTicket与ticket是否相等
    
    if(!redisTicket.equals(ticket)) {
    
    object = new JSONPObject(callback,SysResult.fail());
    
    //删除cookie信息
    
    CookieUtil.deleteCookie("JT_TICKET","/","jt.com", response);
    
    CookieUtil.deleteCookie("JT_USER","/","jt.com", response);
    
    return object;
    
    }
    
    String IP = IPUtil.getIpAddr(request);
    
    Map<String,String> map = jedisCluster.hgetAll(ticket);
    
     
    
     
    
    //1.校验IP是否有效.
    
    if(!IP.equals(map.get("JT_USER_IP"))) {
    
     
    
    //IP地址不正确.
    
    object = new JSONPObject(callback,SysResult.fail());
    
    //删除cookie信息
    
    CookieUtil.deleteCookie("JT_TICKET","/","jt.com", response);
    
    CookieUtil.deleteCookie("JT_USER","/","jt.com", response);
    
    return object;
    
    }
    
     
    
    //2.校验ticket数据信息.
    
    String userJSON = map.get("JT_USER");
    
    if(StringUtils.isEmpty(userJSON)) {
    
     
    
    //IP地址不正确.
    
    object = new JSONPObject(callback,SysResult.fail());
    
    CookieUtil.deleteCookie("JT_TICKET","/","jt.com", response);
    
    CookieUtil.deleteCookie("JT_USER","/","jt.com", response);
    
    return object;
    
    }
    
     
    
    //3.表示校验成功
    
    object = new JSONPObject(callback, SysResult.success(userJSON));
    
    return object;
    
    }
    

      

    二、框架基础知识

    (一)前端知识

    blur()鼠标离开会触发事件(函数)

    Click()鼠标点击会触发事件(函数)

    Val()函数

    val() 方法返回或设置被选元素的值。this输入框的值返回并加入数组

    array.push($(this).val());

     

    prop函数

    jquery中获取对象属性值的一个函数 ,prop函数语法为prop(属性名,[属性值]->赋值

    只有属性名时prop(属性名),意思是获取值

      var cls=$(this).prop("class");

    data函数

    jquery中数据绑定函数

    data函数语法  data(key[value]),给key赋值

    $("#pageId").data("pageCurrent",pageObject.pageCurrent);

    confirm(message)

    message要在 window 上弹出的对话框中显示的纯文本(而非 HTML 文本)

    如果用户点击确定按钮,则 confirm() 返回 true。如果点击取消按钮,则 confirm() 返回 false

    if (!confirm("确认删除吗?"))

    return;

    Checkbox

     <input type="checkbox"> 每出现一次,Checkbox 对象就会被创建。

    input[type='checkbox']

    checked 

    checked 属性 与 <input type="checkbox"> <input type="radio"> 配合使用。

    <input type="checkbox" name="vehicle" value="Car" checked="checked" />

    $("#tbodyId input[type='checkbox']").each(function() {

    if ($(this).prop("checked")) {

    array.push($(this).val());

    }

    })

    (十七)MapPOJO封装数据库数据

    数据库表一行记录映射为一个map对象,多行存储到list。

    使用map存储数据什么优势劣势

    Map封装方便,简单,但可读性差

    Pojo对象封装可读好。

    (十八)AOP相关知识

    Spring中Before通知的目标对象要实现的接口是 MethodBeforeAdvice

    Spring中around通知的目标对象要实现的接口是MethodInterceptor

    1.AOP作用

    名称:面向切面编程

    原有方法进行扩展.在不影响原有的代码的基础之上进行扩展.实现了业务结构的松耦合.

    2.AOP案例

    问题:必然会造成代码的耦合,处理业务的代码和处理事务的代码耦合在一起.

    try{

    tx.begin(); //事务开始

    itemMapper.insert(item);

    tx.commit();//事务提交.

    }cache(){

    tx.rollback();

    }

    1. 切面代码

    try{

    tx.begin(); //事务开始

    业务执行代码

    tx.commit();//事务提交.

    }cache(){

       tx.rollback();

    }

     

    1. 业务代码

    itemMapper.insert(item);

    3.切面

    切面 = 切入点(if判断) + 通知(切面中的方法)

    4.切入点

    1. bean: com.jt.service.itemService  按类匹配1
    2. within(com.jt.service.*) 按类匹配多个

    粗粒度控制

    1. execution(返回值类型 包名.类名.方法(参数列表))

    execution(* com.jt.service..*.*(..))  必须了解

    execution(* com.jt.service..*(..))

    4.@annotation(包名.注解)

    5.通知类型

    1.环绕通知   目标方法执行前后都要执行. 控制方法是否执行.  缓存实现!!!

    2.前置通知   目标方法执行之前执行

    3.后置通知   目标方法执行之后执行

    4.异常通知   目标方法执行抛出异常执行

    5.返回后通知(最终通知)  不管什么时候最后执行的通知

    6.全局异常处理

    @RestControllerAdvice

    public class SystemExeAOP {

     

    /**

     * 如果程序出错,应该在页面中返回什么???

     * 应该返回SysResult.fail();将数据转化为JSON

     * Controller中如果出现问题则执行业务操作

     */

     

    @ExceptionHandler(RuntimeException.class)

    public SysResult fail(RuntimeException e) {

    e.printStackTrace();

    return SysResult.fail();

    }

     

    }

    (十九)Java实体类(entity)

    Entity实体,和PO的功能类似,和数据表一一对应,一个实体一张表。

    就是属性类,通常定义在model层里面 ,一般的实体类对应一个数据表,其中的属性对应数据表中的字段。

    实体是就是Java中的O/R Mapping映射,即数据库中的一个表映射成对应的一个Java,其中还有一个映射文件。给定一个较复杂的实体关系(如一对一,一对多,多对多),应该熟练地写出实体类!

    O/R Mapping的重要部分是表与持久化类之间的映射,现在主要有两种方式:

    1单纯的持久化类映射:表与持久化类之间的映射是通过硬编码的方式写成类.

    2另外的一种是通过XML和持久化类一起来实现映射。

    (二十)js端解决问题方法:

    debugger,console.log,排除法

    (二十一)SpringBoot快捷键:

    Ctrl +Shift+T查类

    Ctrl +T查接口实现类

    Ctrl +O查类的方法,再Ctrl+O查父类方法

    找项目的默认自动配置:

    pring-boot-autoconfigure-2.2.0.RELEASE.jar->/META-INF/spring.factories

    (二十二)CMD命令:

    进入C盘->  cd/

    进入C盘的文件夹->  

    cd C:Users00maven epositoryorgprojectlomboklombok1.18.10

    cd Intel

    进入D盘->  d:

    进入D盘里的文件夹->cd D: omcat     (java -jar 8081.war)

    进入C盘->  c:

    路径:把D:/tomcat这个路径改为cmd,然后回车

    (二十三)Nginx命令:

    前提:nginx的命令执行,必须在nginx的根目录中完成

    命令:

    1.启动nginx     start nginx

    2.重启nginx     nginx -s reload

    3.关闭nginx     nginx -s stop

    (二十四)重要网站

    https://www.google.com

    https://github.com/

    https://stackoverflow.com/   问答网站

    https://mvnrepository.com/ jar包下载

    https://adminlte.io  动吧(开源的前端模板)

    https://www.layui.com/前端框架,经典模块化前端框架

    https://www.bazhuayu.com/八爪鱼,爬网页

    Bootstrap最受欢迎的开源前端框架

    adminLTE 后端模板,整合了bootstrap

    https://www.echartsjs.com/报表库,工作中使用

    网站code.tarena.com.cn

    用户名:tarenacode

    密码code_2017

     

    (二十五)Springboot注解整理

    @SpringBootApplication

    注解一般用于修饰或描述springboot项目的启动类,用于告诉底层系统,

    对此启动类以及所在包以及子包的类进行扫描,检测此类是否是spring管理的对象

    @Component

    注解对类进行描述时表示此类的对象由spring框架创建并管理

    @Scope

    注解用于告诉spring框架此类型对象存储到什么作用域中(不同作用域对应不同的存储方式)对于非web项目,bean对象的作用域一般只有两个

    1singleton  表示此类实例在整个内存中只有一份(默认)

    2prototype 表示此类实例在每层请求都会创造一个实例

    @SpringBootTest 

    注解描述的类是一个单元测试类,此类型的对象可以交给spring容器管理

    @Mapper

    注解用于告诉mybatis框架,此接口的实现类由mybatis框架创建,并且可以将实现类的对象交给spring容器管理,spring容器在存储此类对象时,默认会将类名(首字母小写)作为key存储

    @param 

    ids 可变参数,其中...JDK1.5新特性

    当方法中可变参数在SQL进行引用是,默认可以使用arrayxml映射文件)这个变量接收参数值,也可以在方法参数定义是使用@Param注解对方法参数进行修饰,然后在SQL中使用@Param注解指定的名字获取参数值

    @return

    删除的行数

    @PostConstruct

    注解用于描述对象初始化方法对象初始化时可以执行此方法

    @PreDestroy

    注解用于描述对象销毁方法在对象销毁之前,可以让容器调用此方法,以完成资源释放

    @Setter

    注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。

    @Getter 

    使用方法同上,区别在于生成的是getter方法。

    @ToString

    注解在类,添加toString方法。

    @EqualsAndHashCode

    注解在类,生成hashCodeequals方法。

    @NoArgsConstructor 

    注解在类,生成无参的构造方法。

    @RequiredArgsConstructor

    注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。

    @AllArgsConstructor

    注解在类,生成包含类中所有字段的构造方法。相当于有参方法

    @Data

    注解在类,生成setter/getterequalscanEqualhashCodetoString方法,如为final属性,则不会为该属性生成setter方法。

    @Slf4j

    注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);

    例如:private static Logger log = LoggerFactory.getLogger(GoodsTests.class);

    (二十六)Springboot项目启动后,spring容器怎么启动。

    当程序启动时,首先加载服务器,之后通过服务器启动Spring容器,Spring容器启动后,通过启动类@SpringBootApplication注解,该注解里面的@SpringBootConfiguration注解可以让springBoot中配置类生效,配置文件加载后,通过包扫描等方式创造实例化对象(范围是启动包下的类和子包下的类),程序启动完成。

    Spring容器生命周期有tomcat决定,对象生命周期由容器决定.

    单例对象的生命周期和容器一样。 启动一个tomcat服务器,就有一个JVM,它不共享。

    (二十七)静态代码块:

    类初始化时执行静态代码块

    类加载可以初始化

    (二十八)Java中的变量分类:

    局部变量:方法内定义的变量

    成员变量:把类内、方法体外定义的变量称为成员变量。
    Java中的成员变量分为两种:

    一是没有static修饰的,这些成员变量是对象中的成员,称为实例变量。

    二是有static修饰的,称为类变量(静态变量)。

    (二十九)JVM调优:

    package com.cy.java.jvm;
    
    //-Xmx3m -Xms3m  -XX:+PrintGCDetails  //定义内存,和打印GC详情
    
    public class TestObjectMemory01 {
    
    public static void main(String[] args) {
    
    Obj o=new Obj();
    
    for(int i=0;i<1000000;i++) {
    
    o.doMethod();//连续调用doMethod方法,创造大量对象
    
    }
    
    }
    
    /**
    
     * 类变量,实例变量,方法变量
    
     * 打开逃逸分析后,
    
    声明局部变量,方法内声明的变量,array对象是小对象,直接在栈上分配,GC次数少
    
    如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,无须通过垃圾收集器回收,可以减小垃圾收集器的负载。
    
     *             声明实例变量,array对象是大对象,在堆上分配,GC次数多
    
     *             声明类变量,也在堆分配                             成员变量包含类变量,实例变量。
    
     * @author 000
    
     *-server -XX:-DoEscapeAnalysis 关闭逃逸分析
    
     *方法变量也会被放入堆中
    
     */
    
    static class Obj{//JDK1.8以后系统会默认打开逃逸分析
    
    //byte[] array;   //实例变量
    
    public void doMethod() {
    
    //小对象,未逃逸,有可能直接在栈上分配
    
    byte[] array=new byte[1];  //局部变量
    
    }
    
    }
    
    }
    
    开发中尽量声明局部变量,因为,如果能让对象在栈上分配,那大量的对象就会随着方法的结束而自动销毁了,无须通过垃圾收集器回收,可以减小垃圾收集器的负载。
    
     
    
     
    
    逃逸分析的原理
    
    //Java本身的限制(对象只能分配到堆中),我可以这么理解了,为了减少临时对象在堆内分配的数量,我会在一个方法体内定义一个局部变量,
    
    //并且该变量在方法执行过程中未发生逃逸,按照JVM调优机制,首先会在堆内存创建类的实例,然后将此对象的引用压入调用栈,继续执行,
    
    //这是JVM优化前的方式。然后,我采用逃逸分析对JVM进行优化。即针对栈的重新分配方式,首先找出未逃逸的变量,将该变量直接存到栈里,
    
    //无需进入堆,分配完成后,继续调用栈内执行,最后线程执行结束,栈空间被回收,局部变量也被回收了。如此操作,是优化前在堆中,优化后在栈中,
    
    //从而减少了堆中对象的分配和销毁,从而优化性能。
    

      

     

    (三十)Java四大引用:

    package com.cy.java.refs;
    
    import java.lang.ref.WeakReference;
    
    import java.util.ArrayList;
    
    import java.util.List;
    
     
    
    class RefClass{
    
    /**对象在回收之前会执行finalize()*/
    
    @Override
    
    protected void finalize() throws Throwable {
    
    System.out.println("finalize()");
    
    }
    
    }
    
    //JVM GC
    
    //-Xmx5m -Xms5m  -XX:+PrintGCDetails
    
    public class TestRef01 {
    
    public static void main(String[] args) {
    
    //1.强引用
    
    //RefClass r1=new RefClass();//r1强引用
    
    //r1=null;
    
    //System.gc();//手动GC
    
     
    
    //2.软引用(在GC时,假如内存不足了,有可能会被回收)
    
    //SoftReference<RefClass> r2=
    
    //new SoftReference<RefClass>(new RefClass());
    
    //System.out.println(r2.get());
    
    //System.gc();
    
     
    
    //3.弱引用(只要触发GC,此引用引用的对象就会被回收)
    
    WeakReference<RefClass> r3=
    
        new WeakReference<RefClass>(new RefClass());
    
    System.out.println(r3.get());
    
    //System.gc();
    
     
    
    //4.虚引用(此引用主要用于记录引用的对象是否被销毁了)
    
    //PhantomReference
    
     
    
    List<byte[]> list=new ArrayList<>();
    
    for(int i=0;i<5;i++) {
    
    list.add(new byte[1024*1024]);
    
    }
    
    }
    

      

    (三十一)SpringBoot

    1parent作用.

    SpringBoot旨在简化代码的配置.将公共的jar包进行统一的管理和维护.只要导入parent标签,相当于导入之前的全部公共的jar包程序.

    同时内部定义了全部依赖的版本信息.

    mavenjar包依赖具有传递   A-->B--àC

    2Build标签作用

    3、主启动类作用

    @Target(ElementType.TYPE) 注解的作用域  类上生效

    @Retention(RetentionPolicy.RUNTIME) 标识什么时候有效 编译运行都有

    @Documented 自动关联文档

    @Inherited @Inherited阐述了某个被标注的类型是被继承的。

    @SpringBootConfiguration 让springBoot中配置类生效

    @EnableAutoConfiguration(使能够自动配置) 当依赖某些jar,开启自动配置无需人为的干预.

    @ComponentScan(组件扫描) 以后代码至少主启动类同/

     

    (excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

    public @interface SpringBootApplication {}

    (三十二)Nginx基础命令

    1.启动nginx     start nginx

    2.重启nginx     nginx -s reload

    3.关闭nginx     nginx -s stop

    启动redis

    (三十三)Redis基础命令

    1启动redis

    redis-server redis.conf

    redis-server 6379.conf/6380.conf

    2进入客户端

    redis-cli -p 6379

    3退出客户端: ctrl+c /exit/quit

    4关闭redis/客户端

    redis-cli -p 6379 shutdown

    说明:如果操作的redis是默认的端口号6379 则命令可以简化

    redis-cli    redis-cli shutdown

    5、查进程

    ps -ef |grep redis/java *

    7.杀所有redis关键字的进程

    ps -ef|grep 'redis'|grep -v 'ii'|cut -c 9-15|xargs kill -9

    Kill pid  杀指定几个进程 kill 1 2 3 4

    (三十四)几种常用AOP代码示例:

    1、捕捉业务层异常的切面

    @Component
    
    @Aspect
    
    public class RuntimeAOP {
    
    /**
    
     * execution(* com.jt.service..*.*(..)"
    
     * 拦截service 中的全部类的全部方法的任意参数
    
     * @param joinPoint
    
     * @return
    
     */
    
    //@Pointcut("execution(* com.jt.service..*.*(..))")
    
    //private void webPointcut() {}
    
    //@Around("webPointcut()")
    
    @Around("execution(* com.jt.service..*.*(..))")
    
    public Object around(ProceedingJoinPoint joinPoint) {
    
    Long startTime = System.currentTimeMillis();
    
    Object obj = null;
    
    try {
    
    obj = joinPoint.proceed();
    
    } catch (Throwable e) {
    
    e.printStackTrace();
    
    throw new RuntimeException(e);
    
    }
    
    Long endTime = System.currentTimeMillis();
    
    Class targetClass = joinPoint.getTarget().getClass();
    
    String MethodName = joinPoint.getSignature().getName();
    
    System.out.println("目标对象的类型:"+targetClass);
    
    System.out.println("目标方法的名字:"+MethodName);
    
    System.out.println("方法执行时间"+(endTime-startTime)+"毫秒");
    
    return obj;
    
    }
    
    }
    
     
    

      

    2、运行时间的切面

    @Component
    
    @Aspect
    
    public class RuntimeAOP {
    
    /**
    
     * execution(* com.jt.service..*.*(..)"
    
     * 拦截service 中的全部类的全部方法的任意参数
    
     * @param joinPoint
    
     * @return
    
     */
    
    //@Pointcut("execution(* com.jt.service..*.*(..))")
    
    //private void webPointcut() {}
    
    //@Around("webPointcut()")
    
    @Around("execution(* com.jt.service..*.*(..))")
    
    public Object around(ProceedingJoinPoint joinPoint) {
    
    Long startTime = System.currentTimeMillis();
    
    Object obj = null;
    
    try {
    
    obj = joinPoint.proceed();
    
    } catch (Throwable e) {
    
    e.printStackTrace();
    
    throw new RuntimeException(e);
    
    }
    
    Long endTime = System.currentTimeMillis();
    
    Class targetClass = joinPoint.getTarget().getClass();
    
    String MethodName = joinPoint.getSignature().getName();
    
    System.out.println("目标对象的类型:"+targetClass);
    
    System.out.println("目标方法的名字:"+MethodName);
    
    System.out.println("方法执行时间"+(endTime-startTime)+"毫秒");
    
    return obj;
    
    }
    
    }
    

      

    (三十五)@Controller@RestController的区别?

    1、使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面

    2、如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。

    3、但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面

    (三十六)Linux系统防火墙

    方案一

    1、永久关闭防火墙

    chkconfig iptables off   关闭

    chkconfig iptables on    开启

    2、临时关闭防火墙

    如果当前虚拟机重启之后,则防火墙依然开启.

    service iptables stop 关闭

    service iptables start 开启

    方案二:关闭防火墙

    systemctl stop firewalld.service #关闭防火墙服务

    systemctl disable firewalld.service #禁止防火墙开启启动

     

    systemctl restart iptables.service #重启防火墙使配置生效

    systemctl enable iptables.service #设置防火墙开机启动

    [root@hadoop01 ~]# firewall-cmd --state #检查防火墙状态

    not running #返回值,未运行

    (三十七)Linux系统命令

    IP命令:vim /etc/sysconfig/network-scripts/ifcfg-ens33

    (三十八)Docker常用命令

    1启动容器

    docker run -it centos:7 bash    -i:交互式  -t:终端

    Docker run -dit centos:7 bash   -d:后台运行

    2、查看容器

    docker ps -a

    3、删除容器

    Docker container rm -f idname

    4、进入容器

    Docker exec -it id bash

     

     

    四、代码总结:

    (一)页面控制层的返回页面的优化方法:

    @RequestMapping("menu/menu_list")

    public String doMenuUI() {

    return "sys/menu_list";

    }

    PageController中优化返回UI页面方法。找出共性进行提取,例如:

    @RequestMapping("{module}/{moduleUI}")

    public String doModuleUI(@PathVariable String moduleUI) {

    return "sys/"+moduleUI;

    }

    (三十九)用户名数据库校验:

    服务端代码

    Dao层:

    @Select("select count(*) from sys_users where ${columnName}=#{columnValue}")

    int isExist(String columnName,String columnValue);

    Service层:

    boolean isExists(String columnName,String columnValue);

    @Override

    public boolean isExists(String columnName,String columnValue) {

    int rows=sysUserDao.isExist(columnName,columnValue);

    return rows>0;

    }

    Controller层:

     @RequestMapping("isExists")

      public JsonResult isExists(String columnName,String columnValue) {

     boolean flag=sysUserService.isExists(columnName,columnValue);

      return new JsonResult(flag);

      }

    客户端代码

    <h3 class="msg"></h3>

    <form>

    <input type="text" name="username" class="form-control" id="usernameId">

    <input type="text" name="email" class="form-control"  id="emailId">

    <input type="text" name="mobile" class="form-control"  id="phoneId">

    </form>

    $(function(){

    $("form")

     .on("blur","#usernameId,#emailId,#phoneId",isExists)

     });

     function isExists(){

    var columnName=$(this).prop("name");

    var columnValue=$(this).val();

    var params={"columnName":columnName,"columnValue":columnValue};

    var url="user/isExists";

    $.getJSON(url,params,function(result){

    if(result.data){

    $(".msg").html(columnValue+" exists");

    }

    })

     }

    (四十)Insert时用到useGeneratedKeys="true"

    动吧项目的SysRoleMapper.xml

    <insert id="insertObject"

    parameterType="com.cy.pj.sys.entity.SysRole"

    useGeneratedKeys="true" keyProperty="id">

    <!-- useGeneratedKeys表示使用insert操作对应的自增主键值, keyProperty表示将自增主键值赋值给参数对象的

    哪个属性(entity里面的id属性) -->

    insert into sys_roles

    (name,note,createdTime,modifiedTime,

    createdUser,modifiedUser)

    values

    (#{name},#{note},now(),now(),

    #{createdUser},#{modifiedUser})

    </insert>

    关联(嵌套)查询:

    SysRoleMapper.xml   one2many  

    <!-- resultMap表示结果映射,一般用于自定义映射或一些关联查询中 -->

    <!-- 假如基于id做关联查询,又希望将id值存储到值对象, 可以对id进行专门映射 -->

    property映射到列结果的字段或属性, column数据库中的列名

    <!-- collection一般应用于one2many查询 -->

     <!--

            基于角色id查询角色以及角色对应的菜单id数据

        1)resultMap表示结果映射,一般在使用自定义映射方式

            ,会使用resultMap ;

        2)collection 元素一般用于one2many查询

               在当前应用中是基于角色id查询菜单id并将查询结果

               封装到SysRoleMenuVomenuIds属性上-->

    (四十一)方案1:数据层嵌套查询 -->

    <select id="findObjectById" resultMap="sysRoleMenuVo">

    select id,name,note

    from

    sys_roles

    where id=#{id}

    </select>

     

    <resultMap type="com.cy.pj.sys.vo.SysRoleMenuVo"

    id="sysRoleMenuVo">

    <id property="id" column="id" /><!-- property在对象类中的属性名 -->

    <!-- collection一般应用于one2many查询 -->

    <collection property="menuIds"

    select="com.cy.pj.sys.dao.SysRoleMenuDao.findMenuIdsByRoleId"

    column="id">

    </collection>

    </resultMap>

    <!-- column数据库中的列名,把当前表(sys_roles)的哪个列的值(id)做为参数传递给另一个表(sys_role_menus)查询 -->

      <!-- property映射到列结果的字段或属性 ,这里把查到menu_id值放入menuIds数组 -->

     <!-- 基于角色id查询角色以及角色对应的菜单id数据

    (四十二)方案2:数据层多表查询 -->

       <resultMap type="com.cy.pj.sys.vo.SysRoleMenuVo"

                  id="sysRoleMenuVo">

            <id property="id" column="id"/>  

            <result property="name" column="name"/>

            <result property="note" column="note"/>

            <collection property="menuIds"

                        javaType="list"

                        ofType="int">

                 <id column="menu_id"/>  

            </collection>

       </resultMap>

       <select id="findObjectById"

               resultMap="sysRoleMenuVo">

             select r.id,r.name,r.note,rm.menu_id

             from sys_roles r left join sys_role_menus rm

             on r.id=rm.role_id

             where r.id=#{id}       

       </select>

    (四十三)association

    SysUserMapper.xml    many2oneone2one

    association一般应用于many2oneone2one做关联查询

    <select id="findPageObjects" resultMap="sysUserDeptVo">

    select * from sys_users

    <include refid="queryWhereId" />

    order by createdTime desc

    limit #{startIndex},#{pageSize}

    </select>

    <!-- association一般应用于many2oneone2one做关联查询 在当前应用是基于deptId查询部门信息并将其存储到SysUserDeptVo对象的sysDept属性中。 -->

    <resultMap type="com.cy.pj.sys.vo.SysUserDeptVo"

    id="sysUserDeptVo">

    <association property="sysDept" column="deptId"

    select="com.cy.pj.sys.dao.SysDeptDao.findById">

    </association>

    </resultMap>

    (四十四)resultMap

    resultType:Mybatis可以自动的实现对象封装,

    前提:表的字段域对象的属性一一对应

    resultMap:表示程序员自己手动封装数据

    <!--案例

    user 字段: user_id,user_name

    User对象 属性: userId, userName

     

    resultType:Mybatis可以自动的实现对象封装,

    前提:表的字段域对象的属性一一对应

     

    resultMap:表示程序员自己手动封装数据

      -->

    <!-- <select id="findAll" resultMap="userRM">

    select * from user

    </select>

     

    <resultMap type="User" id="userRM">

    配置原则 1.写主键映射, 2.写其他字段映射

    <id column="user_id"  property="userId"/>

    <result column="user_name" property="userName"/>

    </resultMap>

      

       

      

    五、动吧项目逻辑图分析:

    (一)菜单项CRUD

    查询

    图略;

    数据层方法:List<Map<String,Object>> findObjects();直接用Map封装数据

    映射文件查询需要用到自关联查询,因为需要查到父菜单的名字。

     数据层方法:List<Map<String,Object>> findObjects();

    <select id="findObjects" resultType="map">

             

              <!-- 方案1

              select c.*,p.name parentName

              from sys_menus c left join sys_menus p

              on c.parentId=p.id

              -->

              <!-- 方案2 -->

              select c.*,(

                        select p.name

                        from sys_menus p

                        where c.parentId=p.id

                        ) parentName

              from sys_menus c

             

     </select>

     

    删除

    数据层方法:getChildCount(Integer id);deleteObjectsByMenuId(Integer menuId);

    deleteObject(Integer id);

    业务层:deleteObject(Integer id);

    调数据层getChildCount(Integer id)方法判断是否有子菜单,若有子菜单,就抛出异常,请删除子菜单;调deleteObjectsByMenulddeleteObject删除菜单

     

    (四十五)角色项CRUD

    角色管理业务后台API分层架构及调用关系图

    查询:

    用户发送请求,异步加载页面,前端控制器调doFindPageObjecs方法到控制层,控制层用findPageObjects String name,Integer pageCurrent)方法调业务层;

    业务层方法有findPageObjectsString name,Integer pageCurrent),并调数据层的getRowCount方法得到记录总数和数据层findPageObjects方法;

    数据层接口方法有getRowCount(String name)findPageObjects(String name,Integer startIndex,Integer pageSize);

    数据层返回SysRole类封装的PO对象。业务层返回PageObject类的VO对象,包含PO封装的对象和页面信息。控制层返回http响应对象,也就是jsonResult对象。

    删除:

    用户发送请求,异步加载页面,前端控制器调doDeleteObject方法到控制层,控制层用deleteObject(id)方法调业务层;

    业务层方法有deleteObject(Integer id),与控制层方法保持一致最好,并调数据层的方法;

    数据层接口方法有deleteObjectsByRoleId(Integer roleId)deleteObjectsByRoleId(Integer roleId),deleteObject(Integer id);

    数据层返回rows。业务层返回rows。控制层返回http响应对象,也就是jsonResult对象。

    添加

    业务层方法有:saveObject(SysRole entity,Integer[]menuIds);

    数据层接口方法有:insertObject(SysRole entity);insertObjects(Integer roleId,

    Integer[] menuIds);其中entityPO对象,一个角色可以有多个菜单,多个菜单id用数组封装。菜单与角色联系表sys_role_menus中虽然也有单独id,插入时可忽略,只插入roleIdmenuId

     

    修改

    修改前需要先查出数据呈现到页面:

    数据层方法:SysRoleMenuVo findObjectById(Integer id);   SysRoleMenuVo封装了role表中的id,name,note属性和menuid数组menuIds[]

    映射文件运用了关联嵌套查询,所有只需要一个dao

    业务层方法:SysRoleMenuVo findObjectById(Integer id) ;

     

    数据呈现到页面后,用户修改完需要保存,更新页面:

    数据层方法:updateObject(SysRole entity);

    业务层方法:updateObject(SysRole entity,Integer[] menuIds);

    实现类调用updateObjectdeleteObjectsByRoleIdinsertObjects方法

    六、Bug

    1、SpringBoot项目maven install(打包)

    提示没有在jdk环境下运行。处理办法:window->Java->Installed JREs路径里移除jre,add上jdk。

    2、String字符串转JSON格式:String本身;

    Object格式(User对象)转JSON格式:key,value结构

    @Override

    public void updateCartNum(Cart cart) {

    Cart cartTm = new Cart();

    cartTm.setNum(cart.getNum());

    cartTm.setUpdated(new Date());

    UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<>();

    updateWrapper.eq("user_id", cart.getUserId())

                         .eq("item_id", cart.getItemId());

    cartMapper.update(cartTm, updateWrapper);

    //cartMapper.update(cart, updateWrapper);cart里面包含不更新的数据,所有不能用,自己新建一个对象封装数据

    }

     

    七、Springboot项目搭环境怎么搭:

    导入jar

    Spring Web ->springMVC需要

     

    JDBC API

    MySQL Driver

    MyBatis Framework

    ->SQL需要

     

    Lombok 生成set get 方法

    Spring Boot DevTools  热部署

     

    Thymeleaf ->设置动态html

     

    写配置文件application.properties/application.yml;

  • 相关阅读:
    c/cpp枚举练习
    数据类型的标识
    引用变量
    cocos2dx 3.3 笔记
    希望获取到页面中所有的checkbox怎么做?
    如何判断某变量是否为数组数据类型?
    驼峰函数写法
    trim()函数
    js 获取页面可视区域宽高
    全屏滚动插件
  • 原文地址:https://www.cnblogs.com/yao5758/p/13796971.html
Copyright © 2011-2022 走看看