发表于: 2018-03-04 14:51:53

1 789


今天完成的事情

 1.学习了springboot的yml配置法:

 首先是yml与properties的对比:

 在properties里面的配置如图:

 

 就是我们很熟悉的一种形式,不多说

 然后是yml里面的文件配置:

 

 不同之处发现了吧,yml是一个树状的,一目了然。并且少写了很多代码,当然这个东西的对比还没完:

    1.在properties文件中是以”.”进行分割的, 在yml中是用”:”进行分割; 
    2、yml的数据格式和json的格式很像,都是K-V格式,并且通过”:”进行赋值; 
    3、在yml中缩进一定不能使用TAB,否则会报很奇怪的错误;(缩进特么只能用空格!!!!) 
    4、每个k的冒号后面一定都要加一个空格;
  

 冒号后面加空格在idea中还是很直观的,我截图:

 这是有空格的

  这是没空格的   很直观吧

 所以推荐是用yml后缀的配置文件。


 然后是做一个常规的springboot项目,写好其他东西来配置yml的时候 可能会用到这个东西:

server.context-path

 这个东西在默认的springboot的依赖中是没有的,要降版本号搞成1.4.1.RELEASE才行

 这个东西的作用就是加一个前缀,简单的说就是 现在我的controller的url是/hello ,然后我通过这个配置加上一个前缀:/hh

 那么我访问的时候的url就应该是localhost:8080/hh/hello

 很简单的。

 然后说在配置文件中取值,这里的话呢,就是 用@Value注解;来取值了,也很简单,这块儿有个注意事项,我直接传上来吧

server:
 port: 8080
 #context-path: /girl
 #2.0.0.RELEASE 不支持上面这个东西
#cupSize: B
#上面这个东西需要注意的是要顶头放。。否则就成了server.cupSize了

我这个注释说的很明白了吧,然后取值的操作:

   @Value("${cupSize}")
   private String cupSize;

 就把这个值放到了cupSize这个变量里面。也很简单吧

 但是这时候如果需要注入的值很多的话这样玩儿就很累了,于是我们在配置文件中实用配置文件

girl:
 cupSize: B
 age: 18

就像这样 在配置文件中直接写一个girl前缀的属性,这里为了简单就两个

然后写一个类似实体类的东西:

@Component
@ConfigurationProperties(prefix = "girl")//把这个前缀下面的所有properties全部映射过来
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;
   }
}

 然后的话 我的注释已经说得很明白了,我就不说了

 然后是controlle里面使用这个东西:

@Autowired
private GirlProperties girlProperties;//这里没有加另外的注解,在类似实体类里面。所以爆红@Component

@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String say(){
return girlProperties.getCupSize();
}

这里我的注释也说得很清楚了,包括那个类似实体类的东西里面的@Component的作用,对不对,演示一下不这样做的后果

 写的很清楚,但是这样不影响使用,最好还是写上吧。


然后再说说多个配置文件的情况,也就是生产和开发阶段使用不同的配置

 如图三个配置文件,我只改了端口和里面的参数,然后我们来同时运行:

 首先mvn install 打包,并且以java-jar来启动项目加上使用的配置参数:这里的profile少了个s

 

 选择了dev的配置:

在8081端口启动了,接下来启动idea里面的项目选择在8080端口启动:

 在浏览器分别访问:

 

 可以看到端口和参数不同。这就打成了我们的目标。

 然后关于controller的相关内容昨天已经说过了,这里补一点,返回html页面的时候需要在template下面写好html页面

 然后如果想要两个url都访问到同一个方法的话,就这样:

//下面的url携程一个集合就能够通过hi或者hello来访问同一个方法
@RequestMapping(value = {"/hello","/hi"},method = RequestMethod.GET)
public String say(){
return girlProperties.getCupSize();
}

 很清楚吧

 而与此同时的控制台也会有对应的内容:

 

映射的url都打印出来了

 还有一点补充的内容就是关于url的参数的问题,我都跑通了Demo然后写了注释,大家一看就ok:

 /**
    * @PathVariable拿取url上面的值
    * http://localhost:8080/hello/100
    */
   @RequestMapping(value = "/hello/{id}",method = RequestMethod.GET)
public String show(@PathVariable("id") Integer id){
return "id:"+id;
   }
/**
    *@RequestParam用来获取传统url的参数
    * 类似这样的http://localhost:8080/take?id=100
    */
   @RequestMapping(value = "/take",method = RequestMethod.GET)
//这里的Integer id 不需要和前面的”id“对应,可以使自己的变量
   public String take(@RequestParam("id") Integer id){
return "id:"+id;
   }
/**
    * 接下来不希望取到null值,也就是设定一个默认值的写法
    */
//    @RequestMapping(value = "/take",method = RequestMethod.GET)
//    下面的required含义是是否必传  是false的话就是不必传 ,否则不传的时候会400
//     后面的defauleValue就是默认值,但是不能写int,必须是字符
//    public String take(@RequestParam(value="id",required=false,defaultValue="0") Integer id){
//        return "id:"+id;
//    }

都是干货,我全正好了之后写的各种理解

2.Jpa的学习

 jpa定义了一系列对象持久化的标准

 spring-data-jpa就是spring对hibernate的一个整合

 使用了jpa之后真的是被这种爽快的感觉征服了:

 不用写任何sql语句,不用建表,真的是太刺激了。

 那就说说步骤吧:首先添加依赖数据库和jpa的:

<!--jpa-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--jpa-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>

然后是在配置文件中写上配置:

spring:
 profiles:
   active: dev
datasource:
   driver-class-name: com.mysql.jdbc.Driver
   url: jdbc:mysql://localhost:3306/dbgirl
username: root
password: 123456
jpa:
   hibernate:
     ddl-auto: update
#      create,在每次运行的时候会自动创建一个表,如果已有,会删除重建
#  一共有5个属性 update 是运行的时候创建表,但是会保留数据
#  create-drop 当程序停止的时候就会将表格删除
#  none 什么都不做
#  validate 验证类里面的属性和表节后是否一致,不一致就报错
   show-sql: true
#    这里会显示sql语句

 写成这个样子,这个没啥好说的,主要是我注释的那些内容,写的很清楚了

然后新建一个类:Girl.java

@Entity
public class Girl {
@Id
   @GeneratedValue
   private Integer id;
   private String cupSize;
   private Integer age;

   public Girl() {
}

public Integer getId() {
return id;
   }

public void setId(Integer id) {
this.id = id;
   }

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;
   }
}

那些注解昨天已经说过了,这里说一下这里的无参构造器,这里一定要有这个东西,否则运行报错

这时候直接运行项目,就会自动创建一个girl的数据表 ,根据刚刚那些注解映射过去

 那么接下来开始搞restAPI

首先是写一个GirlController:

@RestController
public class GirlController {

@Autowired
   private GirlRepository girlRepository;
   @GetMapping(value = "/girls")
public List<Girl> girlList(){
return girlRepository.findAll();
   }

@PostMapping(value = "/girls")
public Girl girlAdd(@RequestParam("cupSize") String cupSize,@RequestParam("age") Integer age){
Girl girl = new Girl();
       girl.setCupSize(cupSize);
       girl.setAge(age);
       return girlRepository.save(girl);
   }

@GetMapping(value = "/girls/{id}")
public Girl girlFindOne(@PathVariable("id") Integer id){
return girlRepository.findOne(id);
   }


@PutMapping(value = "/girls/{id}")
public Girl girlUpdate(@PathVariable("id") Integer id,
                          @RequestParam("cupSize") String cupSize,@RequestParam("age") Integer age){
Girl girl = new Girl();
       girl.setId(id);
       girl.setCupSize(cupSize);
       girl.setAge(age);
       return girlRepository.save(girl);

   }
@DeleteMapping(value = "/girls/{id}")
public void girlDelete(@PathVariable("id") Integer id){
girlRepository.delete(id);
   }

@GetMapping(value = "/girls/age/{age}")
public List<Girl> girlListByAge(@PathVariable("age") Integer age){
return girlRepository.findByAge(age);
   }
}

 这里我就全部放上来了包括一个其他的查询

其实也没啥好说的,注意调用的方法就好了 增加和更新使用save,查询全部使用finfall,查询单个使用findone 

 然后新建一个接口继承jpa:

public interface GirlRepository extends JpaRepository<Girl,Integer> {
public List<Girl> findByAge(Integer age);
}

暂时忽略倒数第二行  我们继承jpa之后写上我们对应的类名和id的类型就行了

 然后就可以使用这里面的实例化对象来进行crud操作了,也就是这两行代码:

@Autowired
private GirlRepository girlRepository;

在使用save和delete的时候查看一下源码来确定返回值类型

 接下来来说说查询,上面知识常规的id查询,现在来试试使用age查询,只需要在接口类里面扩展一下就好:

public List<Girl> findByAge(Integer age);

 也就是这行代码,这里需要注意的地方就是方法名的写法,一定要按照这种格式来写,才会如你所愿

对应的controller就是这样:

@GetMapping(value = "/girls/age/{age}")
public List<Girl> girlListByAge(@PathVariable("age") Integer age){
return girlRepository.findByAge(age);
}

 如此这般就行了

 上面的接口我拿postman全部测试过了 都ok

 然后注意事项我应该是都说到了,没说的注释里面也有。

3.事物管理

 比如我现在向同时插入两条数据,我对这个插入的要求是要么都成功插入,要么都不插入:

 于是写一个新的类:

@Service
public class GirlService {
@Autowired
   private GirlRepository girlRepository;

   @Transactional
   public void insertTwo(){
Girl girlA = new Girl();
       girlA.setCupSize("cccc");
       girlA.setAge(18);
       girlRepository.save(girlA);

       Girl girlB = new Girl();
       girlB.setCupSize("z");
       girlB.setAge(55);
       girlRepository.save(girlB);
   }
}
@PostMapping(value = "/girls/two")
public void girlTwo(){
girlService.insertTwo();
}

上面是对应的controller

而我修改熟虑库的字段长度为1,所以A肯定会插入失败,那么加上@Transactionl注解之后,就可以都不插入。

 在运行插入方法时报错:

 

情理之中

 查看数据库,果然一个都没进来

 那么事物管理什么时候用呢?

 只有查询的时候不需要加事物管理,其他时候都尽量加上。

4.接下来是进阶,首先是表单验证

  我们在向数据库插入数据的时候加一个验证,比如现在是禁止插入age<18的数据。

@PostMapping(value = "/girls")
//考虑一下参数很多的时候写这么多param很难受,所以改成对象
public Girl girlAdd(@Valid Girl girl,BindingResult bindingResult){
if (bindingResult.hasErrors()){
System.out.println(bindingResult.getFieldError().getDefaultMessage());
       return null;
   }

girl.setCupSize(girl.getCupSize());
   girl.setAge(girl.getAge());
   return girlRepository.save(girl);
}

  直接上代码吧,参数那里做了修改,方便后期修改实体类的属性,然后上实体类的截图:

@Min(value = 18,message = "未成年少女禁止入内")
private Integer age;

 这里的@Min注解就是设置一个最小值,如果小于这个值,就会发出这样的message;

 controller里面的@Valid打在对象前面,表示需要验证的是这个对象,再通过BindResult对象来获取验证结果

 然后打印

运行插入小于18的数据:

ojbk,达到目的

5.使用aop处理请求

 首先添加依赖,然后设定切面类:

@Aspect
@Component
public class HttpAspect {
//这里拦截这个方法的所有请求,如果想要拦截整个controller的就改成GirlVontroller.*(..)
   @Before("execution(public * com.imooc.controller.GirlController.*(..))")
public void log(){
System.out.println(111111);
   }
@After("execution(public * com.imooc.controller.GirlController.*(..))")
public void doAfter(){
System.out.println(222222);
   }
}

声明切面然后自动装配bean 使用before和after注解对方法进行拦截,分别在方法执行前后打印输出。

 执行效果:

 

 清晰直观。

今天的收获

 以上

 今天遇到的问题

 没啥问题

 明天计划的事情

 继续学习这些内容






返回列表 返回列表
评论

    分享到