7_springboot学习笔记(慕课网)(intellij idea)

#0  视频来源:

       http://www.imooc.com/search/course?words=spring%20boot

7_springboot学习笔记(慕课网)(intellij idea)


#1  intellij idea创建第一个spring boot项目:

(1)  idea绑定jdk:

project sdk那里,选择jdk的安装路径(bin的上一层目录)


(2)  idea绑定maven:
file -- setttings -- Build,Ex,De,--Build Tools -- Maven(先点击当前Maven,然后进去
里面,点击它的子项目比如Repositories!)

(3)  其他:
注意:idea下载时有社区版和旗舰版,社区版在选择springboot项目时选不了!所以只能选择
ultimate版!

创建过程:   new project --   springinitializer --    web -- ……
然后先:  mvn clean install
再:  运行那个主类!

如果在那个主类的同级加一个类或者主类同级的包下加类,然后就可以在浏览器中
访问新加的类了!


(4)热部署:
貌似目前还存在一些问题!
已经解决:
除了添加一个依赖、添加一个插件之外(eclipse中介绍过),
还需要:
CTRL + SHIFT + A --> 查找make project automatically --> 选中 

CTRL + SHIFT + A --> 查找Registry --> 

找到并勾选compiler.automake.allow.when.app.running


(5)注意:
第一,spring boot框架中自带了tomcat,所以,你在运行springboot项目
时不需要手动去绑定tomcat甚至启动等,spring boot帮你做了!而且,如果
你如果不配置端口,那么默认当你启动spring boot时就会使用8080端口!

第二,当你打包好该项目后,在target中找到生成的jar文件,你把这个
jar文件随便拷到哪里,用java -jar xx.jar 命令都可以运行它!


#2  配置文件介绍:
(1)本来是application.properties文件,你也可以新建一个application.yml文件;
比如前者是:   server.port=8083

而后者是: 

      server:

       port:  8083

(2)访问一个java后台方法的注解怎么打;
方法上面  
@RequestMapping(value = "/hello", method = RequestMethod.GET)


(3)要知道怎么获取配置文件中自定义的变量的值,比如你随便定义
比如配置文件中:      myVar1 = zhangsan
则在后台:    

@Value("${myVar1}")
private String name;


(4)将配置文件中的属性的值映射到某个类的变量:
比如,配置文件中:
student.height=170
student.weight=60


然后新定义一个类Student,
然后让该类有两个属性h,w,并定义好get set方法;
然后在该类的上面声明:
@Component
@ConfigurationProperties(prefix = "student")

然后在java类中就可以这样声明变量:
@Autowired
private Student stu;

那么,stu.getH()、stu.getW() 就可以获取刚刚配置文件中配得那两个值了!


(5)可以另外创建两个配置文件:
application-dev.properties
application-prod.properties

然后在application.properties文件中:
如果spring.profiles.active=dev   则:走的是dev的那个配置文件;
如果spring.profiles.active=prod  则:走的是prod的那个配置文件;


如果你直接用java命令跑的话更加灵活:
eg

java -jar xx.jar --spring.profile.active=dev


#3  注解的使用(Controller的使用):

(1)前后端分离思想:

前后端不分离的情况就是:输入的域名往往是访问某个html文件,即直接访问

前台页面;而现在则前后端分离,则是访问到的是某个后台的java类,返回的

是一些json格式的数据而已,而不是某个html页面的数据!


之前用Controller注解,然后在resources/templates/ 下面放比如index.html

,同时在pom文件中声明比如thymleaf模板,然后在某个后台方法中返回

字符串“index”,则你在访问这个后台方法后其实就是直接定位到了/resources/

templates/ 下面的index.html文件了!


现在用RestController注解,则后台方法返回的就是直接的数据,跟前台没有

关系了!!


(2)如何定位到某个类、某个方法:

在类前面加上:

@RestController
@RequestMapping("/hello")
public class XX {……}

在方法面前加上:

@RequestMapping(value = "/say", method = RequestMethod.POST)
public String method(){……}
它等同于: 
@PostMapping(value = "/say")
public String method(){……}

则,如何访问到该方法呢?:

localhost:8085/hello/say   (在postman中选择POST方法)

则:该方法返回什么字符串,则用户就收到什么数据!


(3)带参数的两种方式:

方式一:localhost:8085/hello/say/33

方式二:localhost:8085/hello/say?id=33


方式一实现:

@RequestMapping(value = "/say/{id}", method = RequestMethod.POST)
public String say(@PathVariable("id") Integer myId) {
    return "hello world:" + myId;
}

方式二实现(在postman的parameter那里就要填你需要的参数了!):

@RequestMapping(value = "/say", method = RequestMethod.POST)
public String say(@RequestParam(value = "id", required = true, defaultValue = "5") Integer myId){
    return "hello world:" + myId;
}



#4  数据库操作:
(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>


(2)配置文件:

server.port=8085

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/hellodb?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=12345
spring.datasource.sql-script-encoding=UTF-8

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true



(3)自动生成表的类型的区别:
create:每次都会删掉这张表,重新生成新的表;
update:一般用它,这里不介绍了!(保留原来的表数据!)
……


(4)代码:
先要定义一个实体类;
然后定义一个接口继承自JpaRepository<Person, Integer>,
注:前面填实体类,后面填实体类中id的数据类型;
然后,

package com.ylw.springboot.sb1.dbchildfolder;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(value = "/person")
public class PersonController {

    @Autowired
    private PersonRepository personRepository;

    //增
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public Person personAdd(@RequestParam("age") Integer personAge, @RequestParam("name") String personName) {

        Person person = new Person();

        person.setAge(personAge);
        person.setName(personName);

        return personRepository.save(person);
    }

    //删
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    public void personDelete(@PathVariable("id") Integer personId) {
        personRepository.delete(personId);
    }

    //改
    @RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
    public Person personUpdate(@PathVariable("id") Integer personId,
                               @RequestParam("age") Integer personAge,
                               @RequestParam("name") String personName) {

        Person person = new Person();

        person.setId(personId);
        person.setAge(personAge);
        person.setName(personName);

        return personRepository.save(person);
    }

    //查所有
    @RequestMapping(value = "/lists", method = RequestMethod.GET)
    public List<Person> personLists() {
        return personRepository.findAll();
    }

    //查一个
    @RequestMapping(value = "/list/{id}", method = RequestMethod.GET)
    public Person personList(@PathVariable("id") Integer personId) {
        return personRepository.findOne(personId);
    }
}


(5)自定义查询:
看了JpaRepository<Person, Integer>你会发现,它里面只写了查询所有、
根据id查询的方法,如果你要根据其他属性查找,则需要在自定义的接口
PersonRepository中自己定义一个方法:

package com.ylw.springboot.sb1.dbchildfolder;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface PersonRepository extends JpaRepository<Person, Integer> {

    //自己补充的方法(根据年龄来查找)//注意:这里的命名是固定的,即只能为  findByAge
    public List<Person> findByAge(Integer age);

}

然后在Controller类中:

//根据除id以外的其他属性查找:
@RequestMapping(value = "/lists/age/{age}", method = RequestMethod.GET)
public List<Person> personListByAge(@PathVariable("age") Integer personAge) {
    return personRepository.findByAge(personAge);
}



(6)乱码解决:
如果数据库中添加的数据乱码,则请检查:
Intelij Idea设置开发为:  utf-8
file--settings--editors--file encodings
file--other settings--default settings--editors--file encodings

springboot配置文件中:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/hellodb?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=12345
spring.datasource.sql-script-encoding=UTF-8

数据库在创建的时候:


字符集选择:  utf8 -- UTF-8 Unicode

排序规则选择:  utf8_general_ci


(7)事务管理:

假设某个方法中有多个  操作,

则在该方法的前面加上:

@Transactional
(import org.springframework.transaction.annotation.Transactional;)
则,该方法中的多个操作自然就加上了 事务 的特性!


(8)spring中不用你手动创建的方法
假设你自定义了一个类:
@Service
public class Tool {……}

在别的类中如果要使用一个Tool类的具体对象,则:
public class Main {

	@Autowired
	private Tool tool;

	则:
	tool.xx();
	tool.yy();
}

但注意:自定义的接口
即继承自 JpaRepository<Person, Integer> 的接口,不需要
加上 @Service ,就可以直接用@Autowired,就可以在别的类中使用!


-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
#5 web进阶:
(1)添加对象时某些属性的验证(见sb_2):
	在定义实体类时,需要在属性前面加上比如:

        @Min(value = 18, message = "年龄不得小于18!")

        在添加时,添加的形参对象前面应加上:
	@Valid,比如:

@RequestMapping(value = "/add", method = RequestMethod.POST)
public Person personAdd(@Valid Person person, BindingResult bindingResult) {

    //参数前面加@Valid表示验证该对象中的参数,验证的结果放在BindingResult对象中

    if (bindingResult.hasErrors()) {
        System.out.println(bindingResult.getFieldError().getDefaultMessage());
        return null;
    }

    return personRepository.save(person);
}

(2)什么是AOP?:
它是一种思想,不是具体的技术哈,它的思想是:
面向对象编程中不是会根据业务逻辑分成好多个类吗,其中不同的类之间可能存在一些相同的业务逻辑,这时就可以把这些公共的业务逻辑提取出来,就把这个叫做切面,因此,这样的编程叫做切面编程!比如:最典型的就是登陆,比如,一个系统中有商品类、有订单类、…… 有一个共同点就是,不管你想操作哪个类,比如:添加商品、删除订单等等操作,你都得先判断有没有登陆吧!如果没有登陆则什么也不能做!因此,登陆这个行为就可以抽出来作为一个切面!
比如,假设你的系统中想实现一个这样的功能,在商品类、订单类的一切操作之前,都得先判断用户是否登陆了,如果没有登陆则不能让用户操作这些类的方法,如果没有面向切面,则你的做法是在每个类的每个方法最前面加上一个判断用户是否登陆的判断,但是在aop中怎么实现?:只需要将登陆操作提取出来写在切面中即可!!
(3)spring中实现AOP:
第一步:先把订单类的基础增删改查实现了先(sb-3);
第二步:加入依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
第三步:创建一个切面(普通的java类),在它上面加上这两个注解:
@Aspect
@Component
第一个表示它是一个切面;第二个表示它将来的初始化会交给spring容器
第四步:
在那个切面类中定义一个这样的方法:

@Before("execution(public * com.ylw.springboot.sb3.controller.ProductController.*(..))")
public void judgeLogin() {
    System.out.println("先判断用户是否登录!");
}
则表示: 以后不管运行ProductController这个类中的哪个方法,在运行之前都会调用这里的judgeLogin()方法先!
第五步:after一样的套路,就不用解释了吧!
(4)说一下spring中打印日志的高级做法,平时我们都是用System.out.pirntln()打印日志在控制台,高级的做法如下(以后尽量都用这种方式):
Logger类:(import org.slf4j.Logger;
在每个类中:private final static Logger logger = LoggerFactory.getLogger(类名.class);
使用时,logger.info("");      logger.debug("");   …………
这样的日志详细、高端!
(5)介绍一下在spring boot中,我们的后台有这样的功能:
可以拿到刚刚这个rest请求的具体内容(比如url、方法类型、Ip等等)、同理也可以拿到后台回复的请求中的数据(即response中的数据!)
怎么拿呢?
后台怎么拿到这次请求的request数据?:

import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


//获取该次请求的数据:
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();

//url
logger.info("url is {}", request.getRequestURL());

//method
logger.info("method is {}", request.getMethod());

//ip
logger.info("ip is {}", request.getRemoteAddr());