java入门
这一篇大杂烩的文章,大概是,一些小的零碎的知识点,或者入门的知识点,都会放到这个里面。
语法知识
java8中接口的default方法
https://www.cnblogs.com/zhenghengbin/p/9398682.html
由下而查。
Java8中的接口允许存在default方法,因此官方建议我们直接实现WebMvcConfigurer接口,而不是继承WebMvcConfigurerAdapter 。
Arrays.asList的坑
https://zhuanlan.zhihu.com/p/67224831
java vm
vm启动参数
- https://blog.csdn.net/guyue35/article/details/107957859
- https://www.cnblogs.com/juzii/p/5973516.html
- https://blog.csdn.net/fenglongmiao/article/details/80511512
注意,这部分参数是java后面的参数,而来不是class或jar包后面跟的参数。
java -Dfoo="hello world"
System.getProperty("foo")
spring
ConfigurationProperties
https://blog.csdn.net/yusimiao/article/details/97622666
mybatis、jdbc配置多路数据源的时候,需要用到这个属性。
找不到annotation
定义操作时@Before(value = "@annotation(cn.chaofml.SpringAop.Anno.Action)"),如果跟注解不在一个位置,需要使用绝对的名称。(Import都不行)
具体有坑的代码如下:注解跟LogAspect不在一个文件夹。
package cn.chaofml.SpringAop.Anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
}
package cn.chaofml.SpringAop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAspect {
// 注意,使用了绝对的路径
@Before(value = "@annotation(cn.chaofml.SpringAop.Anno.Action)")
public void before(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "方法开始执行了");
}
}
AfterThrowing
捕捉到错误后,为啥还会终止。甚至around的这个方式,进行捕捉错误,仍然不能?
Pointcut
一个*代表一个层级。
//貌似跟文件夹有关系 cn.chaofml.SpringAop.service.*.* cn.chaofml.SpringAop.*.*
@Pointcut("execution(* cn.chaofml.SpringAop.service.*.*(..))")
public void pointcut(){
}
@Before(value = "pointcut()")
public void before(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "方法执行前");
}
jdbc
jdbc
public class Application {
private static String JDBC_URL = "jdbc:mysql://10.172.26.15:3403/git?useSSL=false&useUnicode=true&characterEncoding=utf8";
private static String JDBC_USER = "dev";
private static String JDBC_PASSWORD = "KxD5hkqkZk9EHPhnkNS3";
public static void main(String[] args) throws SQLException {
// test1();
// test2();
// insertItem();
// updateItem();
deleteItem();
return;
}
public static void updateItem() throws SQLException {
Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
PreparedStatement ps = conn.prepareStatement("update user set username = ? where id = ?");
ps.setObject(1,"罗小红");
ps.setObject(2,23);
int i = ps.executeUpdate();//返回影响的条目
ps.close();
conn.close();
}
public static void deleteItem() throws SQLException {
Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
PreparedStatement ps = conn.prepareStatement("delete from user where id = ?");
ps.setObject(1,23);
int i = ps.executeUpdate();
System.out.println(i);
ps.close();
conn.close();
}
public static void insertItem() throws SQLException {
Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
// 需要返回主键,则需要添加额外的参数
PreparedStatement ps = conn.prepareStatement("insert into user (username,address) values (?,?)",Statement.RETURN_GENERATED_KEYS);
ps.setObject(1,"张大胖");
ps.setObject(2,"河南郑州");
int i = ps.executeUpdate();//影响的条数
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()){
long id = rs.getLong(1); //返回的索引
System.out.println(id);
}
ps.close();
conn.close();
}
/******************
* 使用普通的sql查询,未考虑注入风险
* @throws SQLException
*/
public static void insert1() throws SQLException {
// JDBC连接的URL, 不同数据库有不同的格式 从静态变量中获取
// 获取连接:
Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
Statement statement = conn.createStatement(); //stmt
ResultSet rs = statement.executeQuery("select * from user;");
while (rs.next()){
Long id = rs.getLong(1); // 注意:索引从1开始
String username = rs.getString(2);
String address = rs.getString(3);
System.out.println(id+"#"+username+"#"+address);
}
rs.close();
// 关闭连接:
conn.close();
}
public static void inset2() throws SQLException {
Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
PreparedStatement ps = conn.prepareStatement("select * from user where username = ? ");
ps.setObject(1,"风云");
ResultSet rs = ps.executeQuery();
while(rs.next()){
long id = rs.getLong(1);
String username = rs.getString(2);
String address = rs.getString(3);
System.out.println(id +"#"+username+"#"+address);
}
}
}
mybatis
资源
- mybatis文档
- 江南一点雨-Mybatis入门教程
两种查询模式
SqlSessionFactory factory = SqlSessionFactoryUtils.getInstance();
SqlSession sqlSession = factory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Integer updateId = mapper.updateUserById(user);
System.out.println(updateId);
sqlSession.commit();
xml转义问题
xml实体转义
预定义的实体引用
| < | < | 小于 |
|---|---|---|
| > | > | 大于 |
| & | & | 和号 |
| ' | ‘ | 省略号 |
| " | “ | 引号 |
上面的符号,不能出现在内容区域,需要进行转义,避免跟xml的标记出现冲突。
xml资源
mapper,xml跟java代码放在一起,不在resoures目录下,需要配置pom.xml,如下:
“main” org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): wayne_app.demo3.mapper.UserMapper.getUserById
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
mybatis-config.xml
typeAliases,增加别名。逐个写比较麻烦,直接使用 package,这样所有的包,都可以直接用小写开头的别名了。
mappers,有两种方式,一种是,指定package,这样直接添加一个路径下的所有mapper。
还可以逐个添加。
<?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>
<!--定义别名,这样mapper.xml就可以直接写别名了-->
<typeAliases>
<package name="wayne_app.demo3.model"/>
</typeAliases>
<!-- 配置环境-->
<environments default="development">
<!--配置mysql的环境-->
<environment id="development">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<!--配置连接数据库的4个基本信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--useUnicode=true& &需要转义 & -->
<property name="url" value="jdbc:mysql://10.172.26.15:3403/git?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="dev"/>
<property name="password" value="KxD5hkqkZk9EHPhnkNS3"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<package name="wayne_app.demo3.mapper"/>
</mappers>
</configuration>
mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="wayne_app.demo3.mapper.UserMapper">
<select id="getUserById" resultType="wayne_app.demo3.model.User">
select * from user where id=#{id}
</select>
<select id="getAllUser" resultType="wayne_app.demo3.model.User">
select * from user;
</select>
<select id="getAllUser2" resultType="user">
select * from user;
</select>
</mapper>
统计count
这篇文章比较好count统计,
其他 直接返回map
,https://blog.csdn.net/weistin/article/details/79864150
mapper.xml
只返回一个整数,resultType="java.lang.Integer"
<select id="count" resultType="java.lang.Integer">
select count(*) from question;
</select>
接口如下,即可。
Integer count();
返回分页结果
抽象成一个方法
public class Page {
public static HashMap<String, Object> result(Object rows, Integer count) {
HashMap<String, Object> map = new HashMap<>();
map.put("total",rows);
map.put("rows",count);
return map;
}
}
调用时:
@GetMapping("list")
public HashMap<String, Object> getAll(Integer page, Integer rows){
page = (page-1)*rows;
return Page.result(questionMapper.getAll(page, rows),questionMapper.count());
}
中间的尝试过程:
result(List<Object> rows, Integer count) //第一个参数,定义为数组
//而下面的items,居然是塞不进去
List<Question> items = questionMapper.getAll(page, rows);
//因为 List<Question> List<Object> 类型不匹配 questionMapper.getAll返回的结果,我又不会转成Object
todo:以后如何优化??
java模型与数据库的列
一般java的对象,驼峰命名,而数据库的列,多用_连接。如何让二者保持一致呢?使用resultMap。
使用jdbc直接操作的时候,可以直接拿到数据库对应的列,至于类型,是通过getLong(第n列)这种方式,即,数据库返回的对象,也不一定非要用java对象来承接,但用java对象来接是常用做法。
<resultMap id="questionMapping" type="wayne_app.simpleboot.model.Question">
<id column="q_id" property="qId"/>
<result column="content" property="content" />
</resultMap>
除此,之外,还有一对一,一对多的关系处理。可以用下面来处理。java会自动来解决映射,其实就是为java模型的子属性的对象,的实例化来解决的。
<association property="aid">
一对一关系
</association>
<collection property="bid">
一对多关系
</collection>
其实嘛,我们可以展平它,即,将子的属性下的对象的属性,直接挂到对象上。
实验过,下面的方式申明,及时column、property在返回结果、或java属性中不存在,也没有关系。
<result column="content" property="content" />
通过上面,其实,java模型、resultMap可以增加一些,用不到的属性、甚至不存在的属性,反正,只要存在的时候,就能帮忙给挂上。
java模型类型
上次听同事讲,可以直接将java模型的所有类型都置为 String类型,貌似感觉不规范,但是这样确实非常的快。
sql中的字符串
如下,sql中出现的字符串,单引号、双引号都行。最好使用单引号,因为,postgresql只使用单引号。
select * from question where content = 'hello'
mybatis,参数为啥需要实体类?
假如有如下的查询,我们的if非常的多,即可能需要非常的参数,
<sql id="whereSearch">
<where>
<if test="content !=null">
and content like concat('%',#{content},'%')
</if>
</where>
</sql>
那么对应的接口签名呢?可能如下,但是呢,如果继续增加参数呢?那么参数还要增加……
List<Question> getAll(@Param("page") Integer page,@Param("rows") Integer rows,@Param("content") String content);
但是呢,如果,我们直接使用参数呢?则一切非常的简单化了。
List<Question> getAll(Question question);
<select id="getAll" resultMap="questionMapping" parameterType="...model.Question">
瞬间,非常轻爽了。
同理,对控制器的参数,也是一样的。这样,就把脏活,交给了bean来干。主要逻辑的代码,就非常的清爽了。
POOLED
<dataSource type="POOLED">
POOLED采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。
todo:自带连接池了?为啥springboot里面还使用别的连接池?
mapper namespace
namespace如何命令的呢?
- 接口方式
<mapper namespace="cn.chaofml.demo3.mapper.UserMapper">
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
- 模型
<mapper namespace="cn.chaofml.model.User">
SqlSession sqlSession = factory.openSession();
User user = (User) sqlSession.selectOne("cn.chaofml.model.User.getUserById",1); //使用命令空间
todo:深入研究。
springboot
Result Maps collection does not contain value for
网上找到的答案:
1、select标签内部的resultMap属性,指向的不正确
2、命名空间引入错了
3、resultMap的type或者id指引错误
我实际上发现的问题是:resultMap改成resultType
resultType="wayne_app.simpleboot.model.User"
连接密码错误的时候,不停的闪动,然后有如下错误提示,大概的意思是,密码错了,无法连接,并不停的重试。
reate connection SQLException, url: jdbc:mysql://10.172.26.15:3403/git?useUnicode=true&characterEncoding=utf8, errorCode 1045, state 28000
java.sql.SQLException: Access denied for user ‘dev1’@’10.20.24.223’ (using password: YES)
配置文件切换
启动的时候如何指定配置文件??
spring.config.name=app 指定配置文件
资源打包
https://cloud.tencent.com/developer/article/1700798
https://www.cnblogs.com/newbest/p/9975151.html
打包的时候,pom配置如下:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
主要出现的问题是:
更新了application.properties内容,结果打包后,还就旧的内容。执行
maven clean删除旧的内容,结果打包后,还是没有出现。然后,点了一下重新运行项目,则打包,配置文件顺利的出现了。观察
target/classes/目录下,这个目录可能代表着,打包后,resources资源存放的位置。另外,maven有如下提示,即资源拷贝的情况。
[INFO] Copying 3 resources [INFO] Copying 452 resources
- resources目录下的静态页面,貌似没有打包进去。
增加如下配置,即解决问题。
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
最终的pom配置文件,参见模板。
为什么需要service
除了mapper层,为啥还需要servicec层呢?这是因为mapper层,基本上没有什么逻辑,它只是一个接口层,然后mapper.xml,在这个上面,却没有办法加逻辑。除非把简单的逻辑写在控制器中,但是,没有办法复用。故,再整合一个service层,这一层,主要用来进行逻辑操作。
mapper层,就是“简单的”映射数据库的操作。
https
除了密码必填,以及是否必填,其他都可直接回车。
keytool.exe -genkey -alias tomcathttps -keyalg RSA -keysize 2048 -keystore d:\pem.p12 -validity 365
spring配置。
server.ssl.key-store=classpath:pem.p12
server.ssl.key-alias=tomcathttps
server.ssl.key-store-password=mypassword
thymeleaf
- 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--增加thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 控制器
@GetMapping("/index")
public String index(Model model){
ArrayList<DemoUser> demoUsers = new ArrayList<>();
//省略 变量的初始化
model.addAttribute("list",demoUsers);
return "demo/index"; // 注意最终:templates/ + <return> + .html
}
模板
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <tr th:each="user:${list}"> <td th:text="${user.id}"></td> <td th:text="${user.name}"></td> <td th:text="${user.address}"></td> <td th:text="${user.password}"></td> </tr>
静态资源访问配置
springboot在未配置的情况下,/resouces/static下的文件可直接访问。/resouces/template 是thymeleaf的模板位置文件。
假设新建/resouces/demo/index.html
配置1:
spring.web.resources.static-locations=classpath:/
spring.mvc.static-path-pattern=/**
效果:通过http://localhost:8080/demo/index.html可以访问。但是static的原有映射失效了。
配置2
spring.web.resources.static-locations=classpath:/demo
spring.mvc.static-path-pattern=/**
效果:通过http://localhost:8080/index.html可以访问。但是static的原有映射失效了。省掉了demo。
原有配置可能是:``
spring.web.resources.static-locations=classpath:/static
Idea工具
快捷键
点+名称
这是一系列的操作。常用的如下:
.for 快速循环一个数组 .var 快速定义变量 .sout 输出变量 当然也能直接sout
查看:
File | Settings | Editor | General | Postfix Completion
- for
https://blog.csdn.net/weixin_42369687/article/details/89853679
- 代码修复
对于有问题的代码,可以将光标移过去,并按Alt+Enter来解决。
- 文件重命名文件名右键,Refactor,然后选择rename。但是类中存在引用,改了几次都没有改成功。功能是强大,但是没有达到目的。
普通的项目,打包成jar
https://www.cnblogs.com/blog5277/p/5920560.html
编译报错
错误提示如下:
Error:java: Compilation failed: internal java compiler error
https://blog.csdn.net/q290994/article/details/81474712
貌似需要在好几处都设置一下。比如 java8
其他
数据库配置加密
从一处代码发现,数据库的配置加密了,故找到了如下的文章。