发表于: 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注解对方法进行拦截,分别在方法执行前后打印输出。
执行效果:
清晰直观。
今天的收获
以上
今天遇到的问题
没啥问题
明天计划的事情
继续学习这些内容
评论