JAVA笔记
英文单词
handler 处理
identify 识别
IDEA快捷键
ctrl+alt+s 打开设置
alt+enter 自动修复
ctrl+p 代码提示
shift+enter 换行
ctrl+alt+v 抽取变量
shift+F6 修改名字
ctrl+e 最近打开的文件列表
shift+alt+上下 两行交换
ctrl+shift+u 大小写切换
ctrl+shift+f12 只显示代码编辑区
目录
目录名 | 含义 |
---|---|
controller | 控制器 |
dto | 数据转换对象 |
interceptor | 拦截器 |
mapper | mapper |
model | 数据模型 |
provider | 内容提供 |
service | 服务 |
util | 工具 |
exception | 异常 |
thymeleaf
快速入门
- 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 编写JAVA代码
package com.axunl.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
- src/main/resources/templates文件下创建hello.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
hello thymeleaf
</body>
</html>
- 启动,浏览器输入http://127.0.0.1:8080/hello
语法
<html xmlns:th="http://www.thymeleaf.org">
语法 | 语义 |
---|---|
${session} | session取值 |
th:text | 替换标签里的值 |
th:value | 替换标签value属性 |
th:if | if判断 |
th:fragment | fragment片段 |
th:insert | 插入fragment片段(th:insert=“标签名::片段名”) |
th:each | 循环(th:each="值:${遍历名}) |
@{} | 资源导入 |
注意
- js、css 文件拖拽可以直接引入链接
- 注入Model 可以向网页传递值(model.addAttribute(“name”,“axunl”)=>${name})
- ${#dates.format(变量,时间格式)} 格式日
- 导入爆红,可能存在缓存,要mvn clean一下
SPRINGBOOT
注解
注解 | 语义 |
---|---|
@Controller | 定义控制器,注入ioc容器管理 |
@Value("${名字.属性}") | 注入配置(app.name=>@Value{${app.name}}) |
@RequestMapping | 前端映射URL |
@RequestParam | GET请求参数值 |
@ResponseBody | POST请求参数值 |
@PathVariable | RESTFUL参数值(/user/id=>@PathVariable(name=“id”)) |
@ConfigurationProperties | 注入配置属性(prefix = “person”)=>注入person的所有属性值 |
@ControllerAdvice | 异常处理 |
@ExceptionHandler | 指明异常的处理类型 |
@Transactional | 事务 |
重定向
- return “redirect:index”;
切换环境配置
spring.profiles.active=dev
资源目录
- “classpath:/META-INF/resources/”
- “classpath:/resources/”
- “classpath:/static/”
- “classpath:/public/”
自定义映射(过时)
package cn.axunl.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
return adapter;
}
}
错误页
-
在templates直接创建error.html
-
在templates在建立error文件夹4xx/5xx
-
可有使用的变量
- timesteamp
- status
- error
- exception
- message
- errors
切换数据源
spring:
datasource:
username: root
password: root
url: jdbc:mysql://120.26.71.236:3306/study
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
Interceptor拦截器
package com.axunl.community.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Autowired
SessionInterceptor sessionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(sessionInterceptor).addPathPatterns("/**").excludePathPatterns();
}
}
package com.axunl.community.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class SessionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = (String) request.getSession().getAttribute("token");
return token == null;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
- @EnableWebMvc会拦截所有的资源
删除cookie
Cookie cookie = new Cookie("token", null);
cookie.setMaxAge(0);
自定义异常处理
package com.axunl.community.advice;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(Exception.class)
Object handle(HttpServletRequest request, Throwable ex, Model model) {
HttpStatus status = getStatus(request);
String contentType = request.getContentType();
if ("application/json".equals(contentType)) {
//json错误返回
return null;
} else {
//html错误返回
return new ModelAndView("error");
}
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
日志
logging:
file:
name: com.log
level: error
xml
新建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- ch.qos.logback.classic.filter.ThresholdFilter 临界值过滤器, 过滤掉低于指定临界值的日志
ch.qos.logback.classic.filter.LevelFilter 将过滤器的日志级别配置为INFO,所有INFO级别的日志交给appender处理,非INFO级别的日志,被过滤掉。 -->
<configuration>
<property name="APP_Name" value="sell"/>
//这里为此项目的日志文件夹名
<property name="log.dir" value="./logs"></property>
//这里为日志的存储地址
<timestamp key="bySecond" datePattern="yyyyMMdd HHmmss"/>
<contextName>${APP_Name}</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} [%file:%line] - %msg%n</Pattern>
</layout>
</appender>
<!-- 按日期和大小区分的滚动日志 -->
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/${APP_Name}/info/info.%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- 按日期和大小区分的滚动日志 -->
<appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 必须指定,否则不会往文件输出内容 -->
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 必需要指定rollingPolicy 与 triggeringPolicy 属性 否则不会生成文件-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/${APP_Name}/debug/debug.%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- error级别只按日期滚动生成日志 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 必须指定,否则不会往文件输出内容 -->
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
<!-- <onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>-->
</filter>
<!-- 必需要指定rollingPolicy 与 triggeringPolicy 属性 否则不会生成文件-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/${APP_Name}/error/error.%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 默认值是10MB。 -->
<!-- <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy> -->
</appender>
<!-- 滚动记录文件 -->
<appender name="MONITOR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/${APP_Name}/monitor/monitor.%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="org" level="INFO"/> <!--将org包下面的所有日志级别设为了ERROR -->
<logger name="monitor" additivity="false" level="DEBUG"/>
<logger name="monitor" additivity="false" level="DEBUG">
<appender-ref ref="MONITOR"/>
</logger>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE_INFO"/>
<!-- <appender-ref ref="FILE_DEBUG" /> //上线时 这个需注释掉,debug级别的日志-->
<appender-ref ref="FILE_ERROR"/>
</root>
</configuration>
跳转到外链
@RequestMapping("/login")
public RedirectView login() {
RedirectView redirectView = new RedirectView();
redirectView.setUrl(loginService.getOauthUrl());
return redirectView;
}
MultipartFile
获取上传文件的类
异常
h2
概述
嵌入式数据库
FLYWAY
概述
数据库版本管理
lombok
概述
免去写getting、setting、tostring、日志
用法
- 导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
- 类中写入注解
@Data
- IDEA装上lombok插件
@Slf4j
- 日志注解
package com.axunl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@Slf4j
class SellApplicationTests {
@Test
void contextLoads() {
log.debug("debug");
log.info("info");
log.error("error");
}
}
mysql
遗忘点
- limit 0,10 跳过第0条取10条
GITHUB授权
创建APP
- Setting-Developer settings-New GitHub App
文档
MYBATIS
概述
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
例子
- 配置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>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/study"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</properties>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/axunl/dao/IUserDao.xml"/>
</mappers>
</configuration>
- 配置IUserDao.xml
<?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="cn.axunl.dao.IUserDao">
<select id="findAll" resultType="cn.axunl.domain.User">
select * from user
</select>
</mapper>
- 编写java代码
try {
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
SqlSession session = factory.openSession();
IUserDao userDao = session.getMapper(IUserDao.class);
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
session.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
bean
<?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="cn.axunl.dao.IUserDao">
<select id="findAll" resultType="cn.axunl.domain.User">
SELECT * FROM user
</select>
<insert id="saveUser" parameterType="cn.axunl.domain.User">
INSERT INTO user(username,address,sex,birthday) VALUES (#{username},#{address},#{sex},#{birthday})
</insert>
<update id="updateUser">
UPDATE user SET username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} WHERE id=#{id}
</update>
<delete id="deleteUser" parameterType="java.lang.Integer">
DELETE FROM user WHERE id=#{id}
</delete>
<select id="findOne" parameterType="INT" resultType="cn.axunl.domain.User">
SELECT * FROM user WHERE id=#{id}
</select>
</mapper>
package cn.axunl;
import cn.axunl.dao.IUserDao;
import cn.axunl.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
InputStream is;
SqlSessionFactoryBuilder builder;
SqlSessionFactory factory;
SqlSession session;
IUserDao userDao;
User user;
@Before
public void before() throws Exception {
is = Resources.getResourceAsStream("SqlMapConfig.xml");
builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
session = factory.openSession();
userDao = session.getMapper(IUserDao.class);
user = new User();
user.setUsername("axunl");
user.setAddress("东莞");
user.setSex("女");
user.setBirthday(new Date());
user.setId(1);
}
@After
public void after() throws Exception {
session.close();
is.close();
}
@Test
public void testFindAll() {
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void testSave() {
userDao.saveUser(user);
session.commit();
}
@Test
public void testUpdate() {
userDao.updateUser(user);
session.commit();
}
@Test
public void testDelete() {
userDao.deleteUser(1);
}
@Test
public void testFindOne() {
User user = userDao.findOne(2);
System.out.println(user);
}
}
模糊查询
<select id="findByName" parameterType="string" resultType="cn.axunl.domain.User">
SELECT * FROM user WHERE username like '%${value}%'
</select>
查询后返回id
<insert id="saveUser" parameterType="cn.axunl.domain.User">
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
SELECT last_insert_id()
</selectKey>
INSERT INTO user(username,address,sex,birthday) VALUES (#{username},#{address},#{sex},#{birthday})
</insert>
实体类与mysql字段映射配置
<resultMap id="userMap" type="cn.axunl.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</resultMap>
<select id="findAll" resultMap="userMap">
SELECT * FROM user
</select>
配置别名
<typeAliases>
<package name="cn.axunl.domain"></package>
</typeAliases>
<mappers>
<package name="cn.axunl.dao"></package>
</mappers>
SQL拼接
<select id="findByCondition" parameterType="user" resultType="user">
SELECT * FROM user
<where>
<if test="username!=null">
AND username=#{username}
</if>
<if test="sex!=null">
AND sex=#{sex}
</if>
</where>
</select>
关联一对一
<resultMap id="accountMap" type="cn.axunl.domain.Account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
SELECT u.*,a.uid,a.moeny FROM user AS u,account AS a WHERE u.id = a.uid
</select>
集合
<collection property="user" ofType="user"></collection>
延时加载
setting标签
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
---|---|---|---|
aggressiveLazyLoading | 当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods )。 | true | false | false (在 3.4.1 及之前的版本默认值为 true) |
- mybatis默认开启缓存
缓存
- @Cacheable 有无缓存,有取缓存,无调用方法
- @CachePut 调用方法,更新缓存
- @CacheEvict 删除缓存
注解
SPRINGMVC
配置web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置spring.mvc
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
<context:component-scan base-package="cn.axunl.controller"></context:component-scan>
<!--bean-->
<bean id="InternalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--mvc注解开启-->
<mvc:annotation-driven/>
</beans>
解决乱码
- web.xml加入
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注解
注解 | 语义 |
---|---|
@Controller | 定义控制器,注入ioc容器管理 |
@Value("${名字.属性}") | 注入配置(app.name=>@Value{${app.name}}) |
@RequestMapping | 前端映射URL |
@RequestParam | GET请求参数值 |
@ResponseBody | POST请求参数值 |
@PathVariable | RESTFUL参数值(/user/id=>@PathVariable(name=“id”)) |
@ResponseBody | POST请求参数值 |
@CookieValue | COOKIE值 |
@ModelAttribute | 优先执行中间件 |
@RestController | 资源控制器 |
注解
内置注解
- @Override 重写
- @Deprecated 废弃
- @SuppressWarnings 屏蔽提示
元注解
- @Retention 描述注解的生命周期
- @Target 描述注解的范围
- @Documented 描述其它类型的annotation应该被作为被标注的程序成员的公共API
- @Inherited 表示某个被标注的类型是被继承的
自定义注解
public @interface MyAnnotation {}
反射
与Java反射相关的类如下:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
获取class实例的四种方式
Class c = Main.class;
Class c = Class.forName("cn.axunl.Main");
Class c = new Main().getClass();
ClassLoader loader = Main.class.getClassLoader();
Class c = loader.loadClass("cn.axunl.Main");
JDBC
概述
***JDBC(Java Data Base Connectivity,java数据库连接)***是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
连接方式
-
方式一
Driver driver = new com.mysql.jdbc.Driver(); String url = "jdbc:mysql://localhost:3306/study"; Properties info = new Properties(); info.setProperty("user", "root"); info.setProperty("password", "root"); Connection con = driver.connect(url, info);
-
方式二
Class c = Class.forName("com.mysql.jdbc.Driver"); Driver driver = (Driver) c.newInstance(); String url = "jdbc:mysql://localhost:3306/study"; Properties info = new Properties(); info.setProperty("user", "root"); info.setProperty("password", "root"); Connection con = driver.connect(url, info);
-
方式三
Class c = Class.forName("com.mysql.jdbc.Driver"); Driver driver = (Driver) c.newInstance(); String url = "jdbc:mysql://localhost:3306/study"; String user = "root"; String password = "root"; DriverManager.registerDriver(driver); Connection con = DriverManager.getConnection(url, user, password);
-
方法四(driver加载时static代码块自动注册驱动)
Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/study"; String user = "root"; String password = "root"; Connection con = DriverManager.getConnection(url, user, password);
增删改查
默认已经得到connection对象
-
INSER
PreparedStatement ps = null; String sql = "INSERT INTO user(user_name,user_age)VALUES(?,?)"; ps = con.prepareStatement(sql); ps.setString(1, "axunl"); ps.setInt(2, 21); ps.execute(); if (ps != null) ps.close(); if (con != null) con.close();
-
UPDATE
PreparedStatement ps = null; String sql = "UPDATE user set user_age =? where user_id=?"; ps = con.prepareStatement(sql); ps.setInt(1, 20); ps.setInt(2, 1); ps.execute(); if (ps != null) ps.close(); if (con != null) con.close();
-
DELETE
PreparedStatement ps = null; String sql = "DELETE FROM user where user_id=?"; ps = con.prepareStatement(sql); ps.setInt(1, 1); ps.execute(); if (ps != null) ps.close(); if (con != null) con.close();
-
SELECT
PreparedStatement ps = null; String sql = "SELECT * FROM user where user_id=?"; ps = con.prepareStatement(sql); ps.setInt(1, 1); ResultSet result = null; result = ps.executeQuery(); while (result.next()) { int id = result.getInt(1); String name = result.getString(2); int age = result.getInt(3); System.out.println("id:" + id + " name:" + name + " age:" + age); } if (result != null) result.close(); if (ps != null) ps.close(); if (con != null) con.close();
事务
概述
数据库从一种一直状态转换为另一种一致状态
事务基本要素
1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚
MySQL事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
代码
con.setAutoCommit(false);
con.commit();
SPRING
ApplicationContext与BeanFactory
-
ApplicationContext
立即加载,单例对象适用
-
BeanFactory
懒加载,多例对象适用
Resource resource = new ClassPathResource("bean.xml"); BeanFactory context = new XmlBeanFactory(resource); Hello hello = (Hello) context.getBean("hello");
IOC
概述
控制反转(Inversion of Control,英文缩写为IoC)
例子
- 在resources配置bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="cn.axunl.Hello">
<property name="name" value="hello world"></property>
</bean>
</beans>
- 使用IOC获取对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Hello hello = (Hello) context.getBean("hello");
bean
bane标签
属性 | 含义 |
---|---|
id | 定义id |
class | 注入class全类名 |
factory-bean | 非静态id |
factory-method | 非静态/静态创建对象的方法(非静态id->getInstance()/class::getInstance()) |
scope | 值:singleton 单例,跟容器共存亡、prototype 多例 gc回收、request、session、global session |
property标签
属性 | 含义 |
---|---|
name | 对象属性名 |
value | 对象属性值 |
constructor-arg标签
属性 | 含义 |
---|---|
name | 构造器签名 |
value | 构造器签名的值 |
ref | 引用对象,用来解决Date这样无法识别的类型,传入引用bean的id |
注解
- 配置扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="cn.axunl"></context:component-scan>
</beans>
含义
注解 | 含义 |
---|---|
@Component | 组件定义 |
@Controller | 控制器定义 |
@Service | 服务定义 |
@Repository | 仓库定义 |
@Autowired | 自动注入 |
@Qualifier | 配合@Autowired使用,作用是不唯一id时指定名字注入 |
@Scope | 作用域(singleton 单例,跟容器共存亡、prototype 多例 gc回收) |
@ComponentScan | 自定义配置注解 |
@Bean | bean注解,存入ioc容器 |
@Import | 导入其他注解类 |
@PropertySource | 扫描资源文件 |
@Transactional | 事务管理 |
使用自定义注解类事例
package cn.axunl.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Configuration
@ComponentScan("cn.axunl")
public class SpringConfiguration {
@Bean("runner")
public QueryRunner runner(DataSource source) {
return new QueryRunner(source);
}
@Bean("source")
public DataSource createDataSources() {
ComboPooledDataSource cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/study");
cpds.setUser("root");
cpds.setPassword("root");
return cpds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}
ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
AOP
概述
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
底层
动态代理
final Producer producer = new Producer();
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Float money = (Float) objects[0];
if (method.getName().equals("saleProducer")) {
return method.invoke(producer, money * 0.8f);
} else {
return null;
}
}
});
proxyProducer.saleProducer(1000f);
注意
- 需要引入切入点表达式依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="accountService" class="cn.axunl.service.impl.AccountServiceImpl"></bean>
<bean id="logger" class="cn.axunl.utils.Logger"></bean>
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut-ref="pt"></aop:before>
<aop:pointcut id="pt" expression="execution(* cn.axunl.service.impl.*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
通知类型
- before 前置通知
- after-returning 后置通知,方法正常后执行
- after-throwing 异常通知
- after 后置通知
注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="cn.axunl"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
package cn.axunl.utils;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Logger {
@Pointcut("execution(* cn.axunl.service.impl.*.*(..))")
public void pt() {
}
@Before("pt()")
public void printLog() {
System.out.println("日志调用");
}
}
注意
- 注解时通知存在顺序问题,可以使用环绕通知解决
MyBatis Generator
引入plugins
<!--MyBatis Generator-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
</dependencies>
</plugin>
src/main/resources/generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"></plugin>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://120.26.71.236:3306/community"
userId="root"
password="root">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<javaModelGenerator targetPackage="com.example.demo.model" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.example.demo.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<table tableName="user" domainObjectName="User"></table>
</context>
</generatorConfiguration>
右侧栏运行Plugins/mybatis-generator/mybatis-generator:generate
application.yml
spring:
datasource:
username: root
password: root
url: jdbc:mysql://120.26.71.236:3306/community
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: classpath:mapper/*.xml