springboot入门

入门

版本: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

  1. 先引入
<!--数据库-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  1. 再配置数据库

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

  1. 先引入
<!--开启aop-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 然后在自定义的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
posted @ 2018-11-24 19:35  田云  阅读(289)  评论(0编辑  收藏  举报