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:\Users\000\maven\repository\org\projectlombok\lombok\1.18.10

cd Intel

进入D盘->  d:

进入D盘里的文件夹->cd D:\tomcat     (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;

 

posted @ 2020-10-11 12:33  冯虚御风,不知所止  阅读(172)  评论(0编辑  收藏  举报