目录
入门
版本:2.0.5
项目初始化
- 新建spring init项目
- 可以:添加dev.yml和-prod.yml来区分开发和生成环境配置
- 可以:修改配置文件为application.yml
#可以配置启动文件
spring:
profiles:
active: dev
#可以修改端口号和启动路径
server:
port: 8080
servlet:
context-path: /girl
选择不同配置文件启动:
java -jar target/girl-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
yml自定义属性
先自定义
girl:
cupSize: F
age: 18
再读取:
@Component
@ConfigurationProperties(prefix = "girl")
public class GirlProperties {
private String cupSize;
private Integer age;
public String getCupSize() {
return cupSize;
}
public void setCupSize(String cupSize) {
this.cupSize = cupSize;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
controller
springBoot推荐前后端分离,所以直接返回json
- 注解:@RestController = @Controller + @ResponseBody
springData
- 先引入
<!--数据库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
- 再配置数据库
yml文件
#配置数据库
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db_test
username: root
password: root
jpa:
database: MySQL
show-sql: true
generate-ddl: true
pojo类
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Girl {
@Id
//设置自增,2.0之后要加后面的属性
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String cupSize;
private int age;
public Girl() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCupSize() {
return cupSize;
}
public void setCupSize(String cupSize) {
this.cupSize = cupSize;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
dao层
import org.springframework.data.jpa.repository.JpaRepository;
/**
* girl的操作类
* Integer为主键ID的类型
*/
public interface GirlRepository extends JpaRepository<Girl, Integer> {
/**
* 自定义扩展方法,按照年龄来查询
* @param age
* @return
*/
public List<Girl> findByAge(Integer age);
}
service使用
@Autowired
private GirlRepository girlRepository;
/**
* 查询所有
* @return
*/
@GetMapping("/girls")
public List<Girl> girlList() {
return girlRepository.findAll();
}
/**
* 新增一个女生
* @param cupSize
* @param age
* @return
*/
@PostMapping("/girls")
public Girl girlAdd(@RequestParam("cupSize") String cupSize,
@RequestParam(value = "age",defaultValue = "18") int age) {
Girl girl = new Girl();
girl.setCupSize(cupSize);
girl.setAge(age);
return girlRepository.save(girl);
}
/**
* 查询单个女生
* @param id
* @return
*/
@GetMapping("/girls/{id}")
public Girl girlFindOne(@PathVariable("id") Integer id) {
return girlRepository.findById(id).get();
}
/**
* 更新一个女生
* @param id
* @param cupSize
* @param age
* @return
*/
@PutMapping("/girls/{id}")
public Girl girlUpdate(@PathVariable("id") Integer id,
@RequestParam("cupSize") String cupSize,
@RequestParam(value = "age",defaultValue = "18") int age) {
Girl girl = new Girl();
girl.setId(id);
girl.setCupSize(cupSize);
girl.setAge(age);
return girlRepository.save(girl);
}
/**
* 根据ID删除一个女生
* @param id
*/
@DeleteMapping("/girls/{id}")
public void girlDelete(@PathVariable("id") Integer id) {
girlRepository.deleteById(id);
}
@GetMapping("/girls/age")
public List<Girl> girlsByAge(Integer age) {
return girlRepository.findByAge(age);
}
事务
在service层方法添加 @Transactional注解即可
静态资源
在static下新建js和img和css即可。
表单验证
在domain里面添加注解
@Min(value = 18,message = "年龄不能小于18岁")
private int age;
在controller里面添加
/**
* 新增一个女生
* @param girl
* @return
*/
@PostMapping("/girls")
public Girl girlAdd(@Valid Girl girl, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
return girlRepository.save(girl);
}
AOP
- 先引入
<!--开启aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 然后在自定义的aspect上加注解
aspect/HttpAspect.java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component
@Aspect
public class HttpAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.alvin.controller.GirlController.*(..))")
public void log() {
}
@Before("log()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
LOGGER.info("url={}", request.getRequestURL());
//method
LOGGER.info("method={}", request.getMethod());
//ip
LOGGER.info("ip={}", request.getRemoteAddr());
//类方法
LOGGER.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//参数
LOGGER.info("args={}", joinPoint.getArgs());
}
@AfterReturning(returning = "object", pointcut = "log()")
public void doAfterReturning(Object object) {
LOGGER.info("response={}", object.toString());
}
}
自定义全局异常
先定义一个异常枚举
enums/ResultEnum.java
public enum ResultEnum {
SUCCESS(0, "成功"),
UNKOWN_ERROR(-1, "未知错误"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
先自定义一个异常类
exception/GirlException.java
public class GirlException extends RuntimeException {
private int code;
public GirlException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
再捕获异常
handle/ExceptionHandle
import com.alvin.domain.Result;
import com.alvin.exception.GirlException;
import com.alvin.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class ExceptionHandle {
private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
//判断是否是自定义的异常
if (e instanceof GirlException) {
GirlException girlException = (GirlException) e;
return ResultUtil.error(girlException.getCode(), girlException.getMessage());
} else {
LOGGER.error("【系统异常】",e);
return ResultUtil.error(100,e.getMessage());
}
}
}
单元测试
在要测试的类上ctrl + shift + t 新建测试类
普通测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class GirlServiceTest {
@Autowired
private GirlService girlService;
@Test
public void findById() throws Exception {
Girl girl = girlService.findById(1);
assertEquals(new Integer(20), girl.getAge());
}
}
controller层测试
模拟http请求
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class GirlControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void girlFindOne() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/girls/1"))
.andExpect(MockMvcResultMatchers.status().isOk()) //判断请求状态是否为200
.andExpect(MockMvcResultMatchers.content().string("abc")); //判断结果是否是abc
}
}
项目打包
# 进行单元测试并打包
mvn clean package
# 不进行单元测试并打包
mvn clean package -Dmaven.test.skip=true
linux部署
直接启动
nohup java -jar target/spring-boot-scheduler-1.0.0.jar &
脚本启动和关闭:
start.sh
#!/bin/sh
rm -f tpid
nohup java -jar /data/app/myapp.jar --spring.profiles.active=stg > /dev/null 2>&1 &
echo $! > tpid
stop.sh
tpid=`cat tpid | awk '{print $1}'`
tpid=`ps -aef | grep $tpid | awk '{print $2}' |grep $tpid`
if [ ${tpid} ]; then
kill -9 $tpid
fi
定时器
先在springboot入口类添加注释:@EnableScheduling
@SpringBootApplication
@EnableScheduling
public class GirlApplication {
public static void main(String[] args) {
SpringApplication.run(GirlApplication.class, args);
}
}
再在定时类上添加注解
@Component
public class printScheduler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Scheduled(cron="0/5 * * * * ?")
public void scheduleCheck() {
logger.info("每5秒执行一次");
}
}
整合其他框架
freemarker
引入
<!--freemarker-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
controller层不要使用RESPController注解
templates下面创建ftl格式的html文件(完整的html文件)
用户列表:<br>
<table border="1">
<tr>
<th>id</th>
<th>username</th>
<th>password</th>
<th>name</th>
</tr>
<#list userList as user>
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>${user.name}</td>
</tr>
</#list>
</table>
controller使用
@RequestMapping("/findAllUser")
public String findAllUser(Model model) {
List<User> allUser = service.findAllUser();
model.addAttribute("userList", allUser);
System.out.println(allUser);
return "hello";
}
mybatis
pom引入
<!--mybatis起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--配置xml资源-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
application.yml配置mybaits
mybatis:
type-aliases-package: com.alvin.demo.domain
mapper-locations: classpath:mapper/*Mapper.xml
项目入口加注解
@MapperScan("com.alvin.demo.mapper")
public class DemoApplication {
直接使用即可
如果要整合德鲁伊连接池,可以查看文章
redis
pom引入
<!-- 配置使用redis启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml配置
#Redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
使用
@Autowired
private StringRedisTemplate redisTemplate;
写入:
redisTemplate.opsForValue().set("user", new ObjectMapper().writeValueAsString(user));
读取User类:
String userStr = redisTemplate.opsForValue().get("user");
User user = new ObjectMapper().readValue(user, User.class);
读取List<User>类
String user = redisTemplate.opsForValue().get("userAll");
ObjectMapper objectMapper = new ObjectMapper();
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, User.class);
List<User> userList = objectMapper.readValue(user,javaType);
使用redisCluster集群
# 将配置修改为下面即可:
spring.redis.cluster.nodes=192.168.25.153:7001,192.168.25.153:7002
ElasticSearch
pom引入
<!--ElasticSearch-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
yml配置
#elasticsearch
spring:
data:
elasticsearch:
cluster-name: my-elasticsearch
cluster-nodes: 127.0.0.1:9300,127.0.0.1:9301,127.0.0.1:9302
实体
@Document(indexName = "blog4", type = "article")
public class UserEntity {
@Id
@Field(type = FieldType.Long, store = true)
private long id;
@Field(type = FieldType.Text, store = true, analyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Text, store = true, analyzer = "ik_max_word")
private String content;
……
使用
@Autowired
private UserRepository userRepository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Test
public void createIndex() {
elasticsearchTemplate.createIndex(UserEntity.class);
elasticsearchTemplate.putMapping(UserEntity.class);
}
@Test
public void testUserRepository() {
UserEntity user = new UserEntity();
user.setId(1);
user.setTitle("zhangsan");
user.setContent("123");
userRepository.save(user);
}
如果报错(实例化失败),添加运行时参数
-Des.set.netty.runtime.available.processors=false