Spring Boot

Gradle

国内网络环境更换仓库为阿里云。

1
2
3
4
repositories {
//mavenCentral()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
}

SpringMVC

常用注解

@Controller

负责注册一个bean 到spring 上下文中。

@RequestMapping

注解为控制器指定可以处理哪些 URL 请求。

@GetMapping @PostMapping等价。

@RequestMapping(method = RequestMethod.GET/POST/DELETE/PUT/PATCH)

@RequestBody

该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上 ,再把HttpMessageConverter返回的对象数据绑定到Controller中方法的参数上。

通过 @RequestBody 可以将请求体中的JSON字符串绑定到相应的Bean上,当然,也可以将其分别绑定到对应的字符串上。将JSON字符串中的两个变量的值分别赋予了两个字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$.ajax({
url:"/login",
type:"POST",
data:'{"userName":"admin","pwd","admin123"}',
content-type:"application/json charset=utf-8",
success:function(data){
alert("request success ! ");
}
});

@RequestMapping("/login")
public void login(@requestBody String userName,@requestBody String pwd){
System.out.println(userName+" :"+pwd);
}

将JSON字符串中的两个变量的值赋予了一个User类:

1
2
3
4
5
6
7
8
//User类:
String userName;
String pwd;

@RequestMapping("/login")
public void login(@requestBody User user){
System.out.println(userName+" :"+pwd);
}

@ResponseBody

该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@responsebody后,会直接返回json数据。

1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping("/login")
@ResponseBody
public User login(User user){
return user;
}
//User字段:userName pwd
//那么在前台接收到的数据为:'{"userName":"xxx","pwd":"xxx"}'
//效果等同于如下代码
@RequestMapping("/login")
public void login(User user, HttpServletResponse response){
response.getWriter.write(JSONObject.fromObject(user).toString());
}

@ModelAttribute    

在方法定义上使用:Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute 的方法。

在方法的入参前使用:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参将方法入参对象添加到模型中

@RequestParam

在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法。

(@RequestParam String name)

springmvc会自动根据参数名字来注入,所以要名字一致,不然不会注入

(@RequestParam(name="name") String id)

参数名字不一致的话,需要在@RequestParam后面指定参数名字,才能为后面的参数进行赋值。

(@RequestParam(name="id",required=true) int id)

如果要@RequestParam为一个int型的数据传值,假如前端并未输入,那么将会为int型的数据赋值为null。显然,这是不允许的,直接报错。

可以通过required=false或者true来要求@RequestParam配置的前端参数是否一定要传

如果required为false,那么默认为参数赋值为null。

@PathVariable

绑定 URL 占位符{var}到传入参数。

1
2
3
4
@RequestMapping("/edit/{id}/{name}")
public String edit(Model model, @PathVariable long id,@PathVariable String name) {
return page("edit");
}

与 @RequestParam 的区别:

/edit?Id=${Id}&name=${name}更适合@RequestParam。

/edit/{id}/{name}更适合@PathVariable。

@ExceptionHandler

注解到方法上,出现异常时会执行该方法。

@ControllerAdvice

使一个Contoller成为全局的异常处理类,类中用@ExceptionHandler方法注解的方法可以处理所有Controller发生的异常。

@ResponseStatus

可以将某种异常映射为HTTP状态码。

Mybatis

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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 resource="mysql.properties"></properties>//配置Mysql

<!-- 配置mybatis运行环境 -->
<environments default="development">
<environment id="development">
<!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 -->
<transactionManager type="JDBC" />

<!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
<!-- POOLED 表示支持JDBC数据源连接池 -->
<!-- UNPOOLED 表示不支持数据源连接池 -->
<!-- JNDI 表示支持外部数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>

<mappers>
<!-- 告知映射文件方式1,一个一个的配置
<mapper resource="com/cy/mybatis/mapper/UserMapper.xml"/>-->
<!-- 告知映射文件方式2,自动扫描包内的Mapper接口与配置文件 -->
<package name="com/cy/mybatis/mapper"/>
</mappers>
</configuration>

映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//UserMapper.java
package com.cy.mybatis.mapper;

import java.util.List;

import com.cy.mybatis.beans.UserBean;

public interface UserMapper {
/**
* 新增用戶
* @param user
* @return
* @throws Exception
*/
public int insertUser(UserBean user) throws Exception;
/**
* 修改用戶
* @param user
* @param id
* @return
* @throws Exception
*/
public int updateUser (UserBean user,int id) throws Exception;
/**
* 刪除用戶
* @param id
* @return
* @throws Exception
*/
public int deleteUser(int id) throws Exception;
/**
* 根据id查询用户信息
* @param id
* @return
* @throws Exception
*/
public UserBean selectUserById(int id) throws Exception;
/**
* 查询所有的用户信息
* @return
* @throws Exception
*/
public List<UserBean> selectAllUser() throws Exception;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.mybatis.mapper.UserMapper">
<!-- 自定义返回结果集 -->
<resultMap id="userMap" type="UserBean">
<id property="id" column="id" javaType="java.lang.Integer"></id>
<result property="username" column="username" javaType="java.lang.String"></result>
<result property="password" column="password" javaType="java.lang.String"></result>
<result property="account" column="account" javaType="java.lang.Double"></result>
</resultMap>
<!-- 在各种标签中的id属性必须和接口中的方法名相同 , id属性值必须是唯一的,不能够重复使用。parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型-->
<!-- useGeneratedKeys:( 仅 对 insert 有 用 ) 这 会 告 诉 MyBatis 使 用 JDBC 的getGeneratedKeys方法来取出由数据(比如:像 MySQL 和 SQLServer 这样的数据库管理系统的自动递增字段)内部生成的主键。默认值: false。 -->
<!--keyProperty: (仅对 insert有用)标记一个属性, MyBatis 会通过 getGeneratedKeys或者通过 insert 语句的 selectKey 子元素设置它的值。默认:不设置。 -->
<!--#{}中的内容,为占位符,当参数为某个JavaBean时,表示放置该Bean对象的属性值 -->


<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (username,password,account) values (#{username},#{password},#{account})
</insert>

<update id="updateUser" >
update t_user set username=#{username},password=#{password},account=#{account} where id=#{id}
</update>

<delete id="deleteUser" parameterType="int">
delete from t_user where id=#{id}
</delete>

<select id="selectUserById" parameterType="int" resultMap="userMap">
select * from t_user where id=#{id}
</select>

<select id="selectAllUser" resultMap="userMap">
select * from t_user
</select>


</mapper>

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.cy.mybatis.tools;

import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class DBTools {
public static SqlSessionFactory sessionFactory;

static{
try {
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis.cfg.xml");
//构建sqlSession的工厂
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
}

}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession(){
return sessionFactory.openSession();
}

}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package com.cy.mybatis.service;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.cy.mybatis.beans.UserBean;
import com.cy.mybatis.tools.DBTools;
import com.cy.mybatis.mapper.UserMapper;

public class UserService {


15
public static void main(String[] args) {
insertUser();
// deleteUser();
// selectUserById();
// selectAllUser();
}


/**
* 新增用户
*/
private static void insertUser() {
SqlSession session = DBTools.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
UserBean user = new UserBean("懿", "1314520", 7000.0);
try {
mapper.insertUser(user);
System.out.println(user.toString());
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}
}


/**
* 删除用户
*/
private static void deleteUser(){
SqlSession session=DBTools.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
try {
mapper.deleteUser(1);
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}
}


/**
* 根据id查询用户
*/
private static void selectUserById(){
SqlSession session=DBTools.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
try {
UserBean user= mapper.selectUserById(2);
System.out.println(user.toString());

session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}
}

/**
* 查询所有的用户
*/
private static void selectAllUser(){
SqlSession session=DBTools.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
try {
List<UserBean> user=mapper.selectAllUser();
System.out.println(user.toString());
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}
}


}

SQL

1
2
3
4
编写顺序 SELECTFROMWHEREGROUP BYHAVINGORDER BY
执行顺序 FROMWHEREGROUP BYHAVINGSELECTORDER BY

S显示as为F从..表W找出G以为分组H且筛选出的内容排序。

Radis

Application.properties

1
2
3
4
5
6
7
8
9
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=

@Cacheable

@Cacheable 可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

Thymeleaf

标签引入

<html xmlns:th="http://www.thymeleaf.org">

表达式

${变量表达式}

*{选择表达式} //选择的是上方对象的属性

@{url表达式}

(if) ? (then) //条件运算符

(if) ? (then) : (else)//三目运算符

关键字 功能介绍 案例
th:id 替换id <input th:id="'xxx' + ${collect.id}"/>
th:text 文本替换 <p th:text="${collect.description}">description</p>
th:utext 支持html的文本替换 <p th:utext="${htmlcontent}">conten</p>
th:object 替换对象 <div th:object="${session.user}">
th:value 属性赋值 <input th:value="${user.name}" />
th:with 变量赋值运算 <div th:with="isEven=${prodStat.count}%2==0"></div>
th:style 设置样式 th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''"
th:onclick 点击事件 th:onclick="'getCollect()'"
th:each 属性赋值 tr th:each="user,userStat:${users}">
th:if 判断条件 <a th:if="${userId == collect.userId}" >
th:unless 和th:if判断相反 <a th:href="@{/login}" th:unless=${session.user != null}>Login</a>
th:href 链接地址 <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> />
th:switch 多路选择 配合th:case 使用 <div th:switch="${user.role}">
th:case th:switch的一个分支 <p th:case="'admin'">User is an administrator</p>
th:fragment 布局标签,定义一个代码片段,方便其它地方引用 <div th:fragment="alert">
th:include 布局标签,替换内容到引入的文件 <head th:include="layout :: htmlhead" th:with="title='xx'"></head> />
th:replace 布局标签,替换整个标签到引入的文件 <div th:replace="fragments/header :: title"></div>
th:selected selected选择框 选中 th:selected="(${xxx.id} == ${configObj.dd})"
th:src 图片类地址引入 <img class="img-responsive" alt="App Logo" th:src="@{/img/logo.png}" />
th:inline 定义js脚本可以使用变量 <script type="text/javascript" th:inline="javascript">
th:action 表单提交的地址 <form action="subscribe.html" th:action="@{/subscribe}">
th:remove 删除某个属性 <tr th:remove="all"> 1.all:删除包含标签和所有的孩子。2.body:不包含标记删除,但删除其所有的孩子。3.tag:包含标记的删除,但不删除它的孩子。4.all-but-first:删除所有包含标签的孩子,除了第一个。5.none:什么也不做。这个值是有用的动态评估。
th:attr 设置标签属性,多个属性可以用逗号分隔 比如 th:attr="src=@{/image/aa.jpg},title=#{logo}",此标签不太优雅,一般用的比较少。

内嵌变量

通过#直接访问:

  • dates : java.util.Date的功能方法类。
  • calendars : 类似#dates,面向java.util.Calendar
  • numbers : 格式化数字的功能方法类
  • strings : 字符串对象的功能类,contains,startWiths,prepending/appending等等。
  • objects: 对objects的功能类操作。
  • bools: 对布尔值求值的功能方法。
  • arrays:对数组的功能类方法。
  • lists: 对lists功能类方法
  • sets: 对sets功能类方法
  • maps: 对maps功能类方法

Spring data JPA

基本查询

  • 继承接口

public interface UserRepository extends JpaRepository<User, Long> {}

  • 直接调用方法
1
2
3
4
5
6
7
User user = new User();
userRepository.findAll();
userRepository.findOne(1l);
userRepository.save(user);
userRepository.delete(user);
userRepository.count();
userRepository.exists(1l);
  • 自定义简单查询

自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是

  • User findByUserNameOrEmail(String username, String email);
  • Long countByUserName(String userName);
  • Long deleteById(Long id);

异构数据库多源支持

实体类声明@Entity 关系型数据库支持类型、声明@Document 为mongodb支持类型,不同的数据源使用不同的实体就可以了。(可以混合使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface PersonRepository extends Repository<Person, Long> {

}

@Entity
public class Person {

}

interface UserRepository extends Repository<User, Long> {

}

@Document
public class User {

}

常用注解

@Entity

标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表。如声明一个实体类 Customer,它将映射到数据库中的 customer 表上。

@Table

当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。

常用选项 name,用于指明数据库的表名 @Table标注还有一个两个选项 catalog 和 schema 用于设置表所属的数据库目录或模式,通常为数据库名。

@GeneratedValue

用于标注主键的生成策略,通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment。

@Column

当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明,该属性通常置于实体的属性声明语句之前,还可与 @Id 标注一起使用。

MongoDB

application.properties

spring.data.mongodb.uri=mongodb://name:pass@localhost:27017/test

创建数据实体

1
2
3
4
5
6
7
8
public class UserEntity implements Serializable {
private static final long serialVersionUID = -3258839839160856613L;
private Long id;
private String userName;
private String passWord;

//getter、setter省略
}

创建实体dao的增删改查操作(替换成Repository)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Component
public class UserDaoImpl implements UserDao {

@Autowired
private MongoTemplate mongoTemplate;

/**
* 创建对象
* @param user
*/
@Override
public void saveUser(UserEntity user) {
mongoTemplate.save(user);
}

/**
* 根据用户名查询对象
* @param userName
* @return
*/
@Override
public UserEntity findUserByUserName(String userName) {
Query query=new Query(Criteria.where("userName").is(userName));
UserEntity user = mongoTemplate.findOne(query , UserEntity.class);
return user;
}

/**
* 更新对象
* @param user
*/
@Override
public void updateUser(UserEntity user) {
Query query=new Query(Criteria.where("id").is(user.getId()));
Update update= new Update().set("userName", user.getUserName()).set("passWord", user.getPassWord());
//更新查询返回结果集的第一条
mongoTemplate.updateFirst(query,update,UserEntity.class);
//更新查询返回结果集的所有
// mongoTemplate.updateMulti(query,update,UserEntity.class);
}

/**
* 删除对象
* @param id
*/
@Override
public void deleteUserById(Long id) {
Query query=new Query(Criteria.where("id").is(id));
mongoTemplate.remove(query,UserEntity.class);
}
}

常用注解

@Id

主键,不可重复,自带索引,可以在定义的列名上标注,需要自己生成并维护不重复的约束。如果自己不设置@Id主键,mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。原因可参考上一篇mongo和mysql的性能对比。
在实际业务中不建议自己设置主键,应交给mongo自己生成,自己可以设置一个业务id,如int型字段,用自己设置的业务id来维护相关联的表。

@Document

标注在实体类上,标明由mongo来维护该表。

@Document(collection="mongodb 对应 collection 名")

@Indexed

声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度。
唯一索引的话是@Indexed(unique = true)。
也可以对数组进行索引,如果被索引的列是数组时,MongoDB会索引这个数组中的每一个元素。
也可以对整个Document进行索引,排序是预定义的按插入BSON数据的先后升序排列。

@CompoundIndex

复合索引,加复合索引后通过复合索引字段查询将大大提高速度。

@Field

代表一个字段,可以不加,不加的话默认以参数名为列名。

1
2
3
4
//给映射存储到 mongodb 的字段取别名
//在 java bean 中字段名为 firstName,存储到 mongo 中 key 为 fName
@Field("fName")
private String firstName;

@Transient

被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。