JAVA个人学习笔记(不断更新)
JAVAWEB
request.getSession()
实现了:
如果request有JssesionId这个cookie则根据Jssession获得session
如果没有,创建一个session并且 response返回的时候会返回JssesionId
每一个session的唯一标志就是JssesionId//个人理解
常用API
方法名 | 参数 | 返回值 | 备注 |
---|---|---|---|
Arrays.asList(Object…obj); | 三个相同的类型数据 | List | 三个相同的类型数据 |
selectByPrimaryKey(Integer) | 主键 | Object | 通用Mapper方法 |
StringUtils.join(List,",") | 数组,分隔符 | String | 工具类,将字符串数,用分隔符分割,拼接成字符串 |
str.subString(startIndex.endIndex) | 不解释,看方法名就懂 |
中间件
rabbitmq:
后端
java
Stream流:https://www.cnblogs.com/heliusKing/p/10990221.html
多线程
线程工具类:
public class ThreadUtils {
private static final ExecutorService es = Executors.newFixedThreadPool(10);//创建线程池
public static void execute(Runnable runnable) {//接收一个runnable
es.submit(runnable);//开启一个线程
}
}
方法调用如下:
ThreadUtils.execute(() -> {
createHtml(spuId);
});//lambada表达式,代表新建了一个继承了Runnable的子类对象,里面重写的方法存放的内容就是createHtml(spuId);
Runnable的源码:
public interface Runnable
{
public abstract void run();
}
//其它以后复习
IO流
踩到的坑:判断字符串是否相等
StringA==StringB错误!
a==b | a.equals(b) | |
---|---|---|
a和b为基础数据类型: | 比较值 | 不可用 |
a和b为对象: | 比较地址 | 根据a重写的方法判断 |
包装类和String待补充 |
ThereadLocal :
该类创建的对象是线程共有的(一般放在static final中)
但是该类的属性ThreadLocalMap中的元素不是线程共有的 是每一个线程独一份的
set和get的时候就是为这个属性添加字段(事实上是个数组)
一个项目中可以有多个ThreadLocal的实例,每个实例存放同一种类型在不同线程中的数据
杂七杂八
日志操作
private static final Logger LOGGER=LoggerFactory.getLogger(GoodsHtmlService.class);
LOGGER.error("页面静态化出错: {}" + e,spuId);//至于怎么讲日志输出到控制台 以后再研究
关于RS256算法:公钥加密,私钥解密
? 私钥加密,公钥验证:
? A根据明文和私钥生成signed。生成数据:明文.signed。发送数据到B。
? B用公钥解析数据,没有出错,则代表是A过来的,错了则不是。
关于JWT:是一个token,token的生成可以支持多种算法。RS256是其中一种。内部怎么支持的我们不关心,只关心怎么使用。
cors跨域问题:
? ajax请求 : 返回数据时要求一级二级域名都相同
? cookie: 要求domain的一级域名相同
框架相关
Spring
对象创建过程
Class clazz=Class.forName(classStr);
Object obj=clazz.newInstance();
obj参照@Autowired 从容器中取得对应的对象 确认执行哪个set方法 执行set方法给obj赋值
obj执行@PostConstruct修饰的方法
最后封装到容器中去(over)
spring mvc
8 9 视图解析器:只是将返回的String类型的字符串解析成一个地址,并且返回。
10:这个地方才是对数据的渲染
1 2 3 4 5 6 7:这里都可以看成是在执行controller的内容
Mybatis
? 通用Mapper的 @Transient会在查询时忽略该字段。因为查询时,会要求数据库对每一个值都赋值,如果不忽略,数据库没有给该字段赋值,则报错。
slect(record) 根据某些条件查询,比如说name=“zhangsan”,条件之间默认是并集
selectByPrimaryKey(id) 根据主键查询,返回一个
selectByExample 模糊查询,排序等,用Example设置条件
Mybatis启动原理:
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionfactory=sqlSessionFactioryBuilder.build(inputstream)
sqlSessionFactory:负责从流(配置类)中获得信息:(连接信息,map类名+方法名,以及其所对应的sql语句和封装到的实体类的全限定类名)组成下面这样的结构
这些信息会封装到Configuration然后往下传
Configuration
这里将每个方法的K V结构封装起来 存入到mappers中
SqlSession sqlSession=SqlSessionFactory.openSession;
UserMapper mapper=sqlSession.getMapper(IUserDao.class);//返回一个代理对象。这个mapper是动态的代理,当执行这个mapper里的方法的时候,会进行方法加强.具体流程如下:
User user = mapper.selectAll();
1、获取连接
2、拼接类名和方法名作为Key检索config中的Map获得Sql语句以及返回的参数类型,作为返回值。
关于动态代理,生成代理对象的方法
return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),
new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
//三个参数分别是:1、要加强的对象的类加载器 2、要加强对象的所有接口的字节码数组 3、这个对象中的invoke方法即是加强的方法,这里也可以用lambda表达式。这个对象实现了InvocationHandler.
public class MapperProxy implements InvocationHandler {
//map的key是全限定类名+方法名
private Map<String,Mapper> mappers;
public Connection conn;
public MapperProxy(Map<String,Mapper> mappers,Connection conn){
this.mappers = mappers;
this.conn = conn;
}
/**
* 用于对方法进行增强的,我们的增强其实就是调用selectList方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.获取方法名
String methodName = method.getName();
//2.获取方法所在类的名称
String className = method.getDeclaringClass().getName();
//3.组合key
String key = className+"."+methodName;
//4.获取mappers中的Mapper对象
Mapper mapper = mappers.get(key);
//5.判断是否有mapper
if(mapper == null){
throw new IllegalArgumentException("传入的参数有误");
}
//6.调用工具类执行查询所有
return new Executor().selectList(mapper,conn);
}
}
综上所述
Sqlsessionfactory的作用
1、获得以下几种信息:(这些信息都是来源于Mybaits的配置文件)
? 1、配置Mapper所在的包 (封装map)
? 2、连接
2、创建sqlsession
sqlsession的作用:生成代理对象
在Mybatis中通过配置一个xml来指定:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置properties-->
<properties resource="jdbcConfig.properties"></properties>
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<package name="com.itheima.domain"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
</configuration>
而当其结合Spring 的时候
在Spring配置文件中配置SqlsessionFactory的数据源。
配置文件的位置怎么传过去的呢?我认为Spring中的SqlsessionFactory的实现自动会去读取mapperScanner的信息,然后获取其中的对象。
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 把交给IOC管理 SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 传入PageHelper的插件 -->
<property name="plugins">
<array>
<!-- 传入插件的对象 -->
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<prop key="helperDialect">oracle</prop>
<prop key="reasonable">true</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>
<!-- 扫描dao接口 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.ssm.dao"/>
</bean>
而在springboot中
? 1、SqlsessionFactory自动配置了,
? 2、DateSource自动配置了,但是属性值需要我们导入。
? 3、至于Mapper,可以在Mapper上添加mapper类,也可以在引导类上配置@MapperScan
关于sqlsession的线程安全问题:sqlsession是线程不安全的,所以用sqlsessionFactory,每一个线程访问,就给一个sqlsession。
?
SpringBoot
SpringBoot配置:
注入
String或int等基本数据类型的注入:
配置类:(通过这种方式写入到ioc容器)
@ConfigurationProperties(prefix = "spring.sms") //在这个类中用getter和setter
public class SmsProperties {
private String accessKeyId;
private String accessKeySecret;
private String signName;
private String verifyCodeTemplate;
//getter和setter省略
}
属性导入类:(从ioc拿出来注入到属性导入类中)
@Component
@EnableConfigurationProperties(SmsProperties.class) //在这个类中用Autowired导入配置类的属性
public class SmsUtils {
@Autowired
private SmsProperties prop;
}
//*想要获得注入属性后的SmsUtils实例,必须使用Bean注入:
@Autowired
private SmsUtils smsUtils ;
对象的注入:(代更新)
@Bean
@Autowired
如果想要自定义springmvc的拦截器
1、定义一个类继承WebMvcConfigurer并重写其中的addInterceptors方法 并添加@Configuration
Result风格:
https://www.jianshu.com/p/91600da4df95
1、后台要指定请求方式
2、可以用?id=1&username=aa拼接参数传递或者可以/1/aa传递 二者只能选一种,也可以传递对象,这个看情况。
@GetMapping("/check/{data}/{type}")
public ResponseEntity<Boolean> checkUserData(
@PathVariable("data") String data,
@PathVariable(value = "type" ,required = false) Integer type)
@GetMapping("check")
public ResponseEntity<Void> register(@RequestParam("data") String data,
@RequestParam("type") Integer type)
@PostConstruct 在Bean创建之后执行
springBoot中的拦截器和过滤器:
过滤器实现Filter接口然后注册到容器中 两种注册方式都可以 (在Zuul中一般使用ZuulFilter, 跨域问题使用CorsFilter 方法注入 使用带参构造
拦截器先定义一个拦截器继承HandlerInterceptorAdapter ,然后定义一个类继承WebMvcConfigurer,重写addInterceptors方法写入
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private JwtProperties jwtProperties;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor(jwtProperties)).addPathPatterns("/**");
}
}//这里的JwtProperties在注册拦截器的时候才使用
SpringData JPA
redis:
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置
spring:
redis:
host: 192.168.64.129
3、使用
private StringRedisTemplate redisTemplate;//创建模板,String代表序列化成String类型的数据
BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(key);//获得一条记录,如果没有,则创建May<String,Map<Object,Object>>
hashOps.values();//这些方法可以顾名思义,但是要记住,hashOps所有方法都是操作hashOps内部的
hashOps.haskey();
?
前端
JAVASCRIPT
? elasticsearch安装:https://blog.csdn.net/qq_43636087/article/details/103439087
解构表达式:
? 即是将对象用一个定义好的模板接收,然后对象里的元素会被拆分出来
对象:
const person = {
name:"jack",
age:21,
language: ['java','js','css']
}
// 解构表达式获取值
const {name,age,language} = person;//前半段就是接收的模板
// 打印
console.log(name);
console.log(age);
console.log(language);
数组:
let arr = [1,2,3]
const [x,y,z] = arr;// x,y,z将与arr中的每个位置对应来取值
// 然后打印
console.log(x,y,z);
在函数的参数中使用:
1、
const person = {
name:"jack",
age:21,
language: ['java','js','css']
}
function hello(person) {
console.log("hello," + person.name)
}
var hi = ({name}) => console.log("hello," + name);//用解构模板接受了,函数中可以使用
2、
ly.http.post("/search/page", this.search).then({data})=>{
this.goodsList=data.items;
});//这里promise对象最后会调用then这个回调函数,然后传入resp(响应对象),这里用{data}接收,获得里面的data
this.filters.find(f=>f.k==="品牌";});///filters是一个数组,filter是回调函数,f代表集合中每个元素,f从filters集合中获得k属性为品牌的对象。
const keys = Object.keys(this.search.filter);
return this.filters.filter(f => !keys.includes(f.k));//filters是一个数组,filter是回调函数,f代表集合中每个元素,把filters数组中的符合!keys.includes(f.k)的f元素抽取出来,组成一个新的集合
list.push//给集合赋值。
javascript给Map加属性:
obj["属性名"]=“属性值”,
obj.属性名=属性值
const index = Object.values(this.indexes).join("_");//获得index的value值组成的数组,并将其拼接成字符串 如果this.indexes的key是数组的话,那么新组成的数组会按照key的从小到大的顺序排列
const object = {5:35,7:12,8:12,3:80};
Object.values(object) 的结果是 [80, 35, 12, 12]
在vue中:发送ajax请求后,可以指定transformResponse参数,处理后台传过来的数据
ly.http.post("/order/order", this.order,{
transformResponse: [
function(data){
return data;
}
]
}).then
在es6中 Object.assign(A,B,C);将B,C对象的属性 拼接到A后面去
范例:
Object.assign(this.order, obj, {
orderDetails,
totalPay: this.totalPay,
actualPay: this.actualPay,
});
es6中this指向:<http://www.imooc.com/article/288214?block_id=tuijian_wz#comment
checkbox:
在原生vue中:checked属性表示是否绑定
在vue中:<input type="checkbox" v-model="selected" name="" :value="cart" /> value的数据是否在v-model中 如果在 就选中 如果不在 就不选中
对数组arrays遍历并依次用回调函数处理其元素,其中,前一个元素是上一次运算的结果,如果是第一次运算,则是该函数的第二个参数
arrays.reduce((c1, c2) => c1 + c2.price * c2.num, 0);
? webpack:类似于tomcat
? npm: 类似于maven
? webpack+nom:类似于maven集成tomcat
消息队列
? https://segmentfault.com/a/1190000013039660
关于回调函数和promise以及异步:
1、[添加链接描述](https://blog.csdn.net/liwusen/article/details/54142748?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task)
2、[添加链接描述](https://www.baidu.com/s?wd=js%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C&rsv_spt=1&rsv_iqid=0xee8725b6002268ec&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=1&rsv_dl=tb&oq=js%25E5%25BC%2582%25E6%25AD%25A5&inputT=6082&rsv_t=33faFD7XzbzseJE4NT49JI5KCESV/CzErUHlFudWJyzhY/lcqW7NXcbExCSTLoJ2g4m4&rsv_sug3=16&rsv_sug1=14&rsv_sug7=100&rsv_pq=b25f4dd7000251fc&rsv_sug2=0&rsv_sug4=6201)
promise:
var p=new Promise(function(resolved))
//在这里进行处理。也许可以使用ajax
setTimeout(function(){
var result=10*5;
if(result===50){
resolve(50); //异步成功并返回数据
}else{
reject(new Error('Bad Math')); //异步失败
}
},1000);
});
p.then(function(result){
console.log('Resolve with a values of %d',result);
});
p.catch(function(){
console.error('Something went wrong');
});
在promise里面定义代码;p.then(“成功后的回调函数”).catch(“失败后的回调函数”);
promise使用时直接调用里面的函数
async await
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('done!'), 1000)
})
let result = await promise // 直到promise返回一个resolve值(*)
alert(result) // 'done!'
}
f()
async 返回一个promise,async里面可以用await,代表执行完这个promise才能继续执行
this:
下一篇: selinux的初级管理