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启动参数

注意,这部分参数是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

资源

两种查询模式

mapper namespace

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&    &需要转义  &amp; -->
                <property name="url" value="jdbc:mysql://10.172.26.15:3403/git?useUnicode=true&amp;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>

其实嘛,我们可以展平它,即,将子的属性下的对象的属性,直接挂到对象上。

实验过,下面的方式申明,及时columnproperty在返回结果、或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">
  1. POOLED采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现

  2. UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。

  3. JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。

    原文链接:https://blog.csdn.net/QGhurt/article/details/106431398

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

    探究:https://www.h5w3.com/34043.html

查看:

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

其他

数据库配置加密

从一处代码发现,数据库的配置加密了,故找到了如下的文章。

https://www.jb51.net/article/204301.htm