java 知识点 23(spring的点点滴滴、spring boot上传下载、redis、gradle项目管理工具、java版本问题)

1、spring的点点滴滴

1.1、Spring IOC

IOC容器:就是具有依赖注入功能的容器。Spring中BeanFactory是IOC容器的实际代表者。
在这里插入图片描述

1.2、Spring AOP

AOP:面向切面编程,动态代理
OOP:面向对象编程

OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。

比如,我们可以为动物这个集合,同时引入跑、走、叫、吃,这些对象,oop很容易做到。
当我们想为动物、植物、房屋等不同集合、没有关联的集合,同时引入高度记录、耐高温强度等这样的需求oop很难做到。aop可以很方便的实现。

我们常常用AOP做日志功能、安全性、异常处理等
便于减少系统的重复代码,降低模块间的耦合度,利于维护

spring aop有五种通知类型:

  1. 前置通知:在目标方法前运行(@Before)
  2. 后置通知:在目标方法结束后 ,不管有没有异常(@After)
  3. 返回通知:在目标方法正常返回值后运行(@AfterReturning)
  4. 异常通知:在目标方法出现异常后运行(@AfterThrowing)
  5. 环绕通知:动态代理,需要手动执行joinPoint.procced()(其实就是执行我们的目标方法执行之前相当于前置通知, 执行之后就相当于我们后置通知(@Around)

1.3、BeanDefinition

在加载每个bean之前,BeanDefinition先会为每个bean贴上一些标签(就像这个bean的说明书一样)。贴上例如类名、scope、属性、构造函数参数列表、依赖的bean、是否是单例类、是否是懒加载等这些信息。
在这里插入图片描述

就像水果在加工厂流水线上,BeanDefinition就是一个筛选、并贴说明书的机器。

BeanDefinition是一个接口,是一个抽象的定义,实际使用的是其实现类,如 ChildBeanDefinition、RootBeanDefinition、GenericBeanDefinition等。

BeanDefinition的执行结果最终会以 map(bean名字,bean说明书)的形式存储。
在这里插入图片描述
这个map的具体名字叫 beanDefinitionMap()

1.4、注解@RequestParam如何使用加与不加的区别

加上注解@RequestParam表示该参数在 url中必须要有,否则报错
在这里插入图片描述

在这里插入图片描述
平时我们在使用的时候不加注解也可以传递参数(并且不加注解,url中没有参数也不会报错)
在这里插入图片描述
在这里插入图片描述
注解@RequestParam还有几个参数可以配置

required 表示是否必须,默认为 true,必须。
defaultValue 可设置请求参数的默认值。
value 为接收url的参数名(相当于key值)。

当然这样的限制是可以选择的,@RequestParam里添加required=false来关闭必须参数的限制,这样就和第一种不带注解的效果一样了
在这里插入图片描述

1.5、Spring中Model、ModelMap及ModelAndView之间的区别

springmvc中,直接在controller方法形参上定义默认类型的对象,可以使用这些对象。

  • HttpServletRequest对象
  • HttpServletResponse对象
  • HttpSession对象
  • Model/ModelMap对象

1、Model是一个接口,包含addAttribute方法。
2、ModelMap类实现了Map接口。
3、ExtendedModelMap继承了ModelMap类。

Model通过addAttribute方法向页面传递数据
在这里插入图片描述
Model可以接收各种类型的数据,如果接收的数据是List,那么这个时候Model实际上是ModelMap。

ModelAndView通过addObject方法向页面传递数据
在这里插入图片描述
Model与ModelAndView的区别

第一点:Model只是用来传输数据的,并不会进行业务的寻址。ModelAndView 却是可以进行业务寻址的;所以Model的返回值是url地址,而ModelAndView的返回值是ModelAndView对象;

第二点:Model是每一次请求可以自动创建,但是ModelAndView 是需要我们自己去new的。所以使用Model时Controller的参数是Model。

1.6、@ModelAttribute模型属性

@ModelAttribute:用来

@ModelAttribute 注释的方法会在Controller每个方法执行之前都执行,
因此对于一个Controller中包含多个URL的时候,要谨慎使用。

它可以使用在

  1. 应用在方法上
  2. 应用在方法的参数上
  3. 应用在方法上,并且方法也使用了@RequestMapping

应用在无返回值的方法上
在这里插入图片描述

如上例子中:
请求/modelattribute/method?abc=aaa,会先执行myModel方法,再接着执行method方法
请求 /modelattribute/method时,Model会被带到页面上

把myModel和method合二为一
在这里插入图片描述

应用在有返回值的方法上

@ModelAttribute
public String myModel(@RequestParam(required = false) String abc) {
    return abc;
}

@ModelAttribute
public Student myModel(@RequestParam(required = false) String abc) {
    Student student = new Student(abc);
    return student;
}

@ModelAttribute
public int myModel(@RequestParam(required = false) int number) {
    return number;
}

返回值对象会被默认放到隐含的Model中,在Model中的key为返回值首字母小写,value为返回的值。

上面3种情况等同于:

model.addAttribute("string", abc);
model.addAttribute("student", student);
model.addAttribute("int", number);

@ModelAttribute还可以添加value属性

@ModelAttribute(value = "num")
public int myModel(@RequestParam(required = false) int number) {
    return number;
}

//这样就相当于 model.addAttribute("num", number);

使用@ModelAttribute注解的参数

@Controller
@RequestMapping(value = "/modelattribute")
public class ModelAttributeParamController {

    @ModelAttribute(value = "attributeName")
    public String myModel(@RequestParam(required = false) String abc) {
        return abc;
    }

    @ModelAttribute
    public void myModel3(Model model) {
        model.addAttribute("name", "zong");
        model.addAttribute("age", 20);
    }

    @RequestMapping(value = "/param")
    public String param(@ModelAttribute("attributeName") String str,
                       @ModelAttribute("name") String str2,
                       @ModelAttribute("age") int str3) {
        return "param";
    }
}

从代码中可以看出,使用@ModelAttribute注解的参数,意思是从前面的Model中提取对应名称的属性。

应用在方法上,并且方法上也使用了@RequestMapping

@Controller
@RequestMapping(value = "/modelattribute")
public class ModelAttributeController {

    @RequestMapping(value = "/test")
    @ModelAttribute("name")
    public String test(@RequestParam(required = false) String name) {
        return name;
    }
}

这种情况下,返回值String(或者其他对象)就不再是视图了,而是放入到Model中的值,此时对应的页面就是@RequestMapping的值test。
如果类上有@RequestMapping,则视图路径还要加上类的@RequestMapping的值,本例中视图路径为modelattribute/test.jsp。

1.7、@RequestBody和@RequestParam区别

@RequestBody这个一般处理的是在ajax请求中声明contentType: "application/json; charset=utf-8"时候。也就是json数据或者xml(我没用过这个,用的是json)

@RequestParam这个一般就是在ajax里面没有声明contentType的时候,为默认的。。。urlencode格式时,用这个。

2、spring boot

2.1、上传附件

需要的依赖web、commons-fileupload、thymeleaf

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在resources/templates下 新建u.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
	<form method="post" action="/upload" enctype="multipart/form-data" >
        <input type="file" value="请选择附件..." title="上传附件" /><br>
        <input type="submit" value="提交">
	</form>
</body>
</html>

新建控制类TestController.java

如下是保存在G盘根目录下

package com.haha.myboot05.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Date;

@Controller
public class TestController {
    @RequestMapping("/u")
    public String uploadFile(){
        return "u";
    }

    @RequestMapping(value="/upload",method = RequestMethod.POST)
    public String upload( MultipartFile file) throws IOException {
        //用来检测程序运行时间
        long  startTime=System.currentTimeMillis();
        System.out.println("正上传文件:"+file.getOriginalFilename());
        try {
            //获取输出流
            OutputStream os = new FileOutputStream("G:\\"+new Date().getTime()+file.getOriginalFilename());
            //获取输入流 CommonsMultipartFile 中可以直接得到文件的流
            InputStream is=file.getInputStream();

            int temp;
            //一个一个字节的读取并写入
            while((temp=is.read())!=(-1))
            {
                os.write(temp);
            }
            os.flush();
            os.close();
            is.close();

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        long  endTime=System.currentTimeMillis();
        System.out.println("方法一的运行时间:"+String.valueOf(endTime-startTime)+"ms");
        return "u";
    }
}

然后运行,访问http://localhost:8080/u就可以了

2.2、下载

在Controller里面

    @RequestMapping("/download")
    public ResponseEntity downloadImg() throws Exception{
        FileSystemResource file = new FileSystemResource("src/main/resources/1602249098889.png");
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition","attachment; filename=123.png");
        return ResponseEntity
                .ok()
                .headers(headers)
                .contentLength(file.contentLength())
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(new InputStreamResource(file.getInputStream()));
    }
}

2.3、spring boot + redis

spring boot在1.x.x的版本时默认使用的jedis客户端,
现在是2.x.x版本默认使用的lettuce客户端。

区分一下这两:

  • Jedis :直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
  • Lettuce:是基于Netty的,连接实例可以在多个线程间并发访问,因为StatefulRedisConnection是线程安全的,所以一个连接实例可以满足多线程并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。lettuce主要利用netty实现与redis的同步和异步通信。
2.3.1、redis安装

redis官方文档:http://redis.cn/documentation.html

windows下安装redis

下载地址:https://github.com/tporadowski/redis/releases/download/v5.0.9/Redis-x64-5.0.9.zip
备用(下载zip包):https://github.com/tporadowski/redis/releases

下载完解压出来的目录下执行启动命令

redis-server.exe redis.windows.conf

在这里插入图片描述
redis的可视化管理工具: Redis Desktop Manager

安装包:https://pan.baidu.com/s/1Jvr9MbgFn4UJh4M1AMo3gA
提取码:3i9b

在这里插入图片描述
除此之外还可以将redis加入windows系统,开机自启
安装redis服务

redis-server --service-install redis.windows.conf

检查安装是否成功,搜索redis服务
在这里插入图片描述
点击设置为开机自启

2.3.2、SpringBoot+ Redis 存数据

系统:windows
开发工具:idea
项目管理工具:maven
配置文件:yaml

这里使用的是 springboot 2.X.X ,Lettuce客户端

新建spring’项目(只勾选一个web的依赖就行)

再手动加入redis的依赖

	<!--redis依赖包-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>

配置完就可以写一个测试类试试

package com.haha.bootandredis;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;

@SpringBootTest
class BootandredisApplicationTests {

    @Autowired
    StringRedisTemplate stringRedisTemplate; //操作key-value都是字符串,最常用

    @Test
    public void test01(){
        //字符串操作
        stringRedisTemplate.opsForValue().append("msg","coder");

        //列表操作
        stringRedisTemplate.opsForList().leftPush("mylist","1");
        stringRedisTemplate.opsForList().leftPush("mylist","2");
    }
}

如果引入了mysql的依赖必须加MySQL的配置内容,否则会报错
java.lang.IllegalStateException: Failed to load ApplicationContext

启动,运行
然后查看redis,多了两个我们新插入的内容
在这里插入图片描述

对于Redis的五大常用数据类型都提供了方法

String(字符串)、List(列表)、Set(集合)、Hash(散列)、ZSet(有序集合)
stringRedisTemplate.opsForValue();[String(字符串)]
stringRedisTemplate.opsForList();[List(列表)]
stringRedisTemplate.opsForSet();[Set(集合)]
stringRedisTemplate.opsForHash();[Hash(散列)]
stringRedisTemplate.opsForZSet();[ZSet(有序集合)]

2.3.3、springboot + mybatis +redis

插入依赖

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

配置mybatis和redis

注意redis端口、mysql端口、库名、账号密码

#redis配置
#Redis服务器地址
spring:
  redis:
    host: 127.0.0.1
    #Redis服务器连接端口
    port: 6379
    #Redis数据库索引(默认为0)
    database: 0
  datasource:
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&useSSL=true&serverTimezone=GMT
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

在test库里新建表user

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8;


INSERT INTO user VALUES (1,"lili","20200909",1,"aaaaa");
INSERT INTO user VALUES (2,"yaya","20200910",2,"bbbbb");

新建一个实体类user

import java.io.Serializable;
import java.util.Date;

public class user implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    @Override
    public String toString() {
        return "user{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

新建UserMapper类

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(int id);
}

自定义序列化类MyRedisConfig,将存储在Redis的对象序列化为json格式,不会产生乱码

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

@Configuration
@EnableAutoConfiguration
public class MyRedisConfig {
    @Bean
    public RedisTemplate<Object, User> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object, User> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        Jackson2JsonRedisSerializer<User> ser = new Jackson2JsonRedisSerializer<>(User.class);
        template.setDefaultSerializer(ser);
        return template;
    }
}

工具类RedisUtil

里面写了三个功能 判断是否存在key、从redis中获取值、向redis插入值

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

//工具类中使用Autowired注解需要加上Compoent
@Component
public class RedisUtil {
        @Autowired
        RedisTemplate redisTemplate;   //key-value是对象的

        //判断是否存在key
        public  boolean hasKey(String key){
            return redisTemplate.hasKey(key);
        }

        //从redis中获取值
        public  Object get(String key){
            return  redisTemplate.opsForValue().get(key);
        }

        //向redis插入值
        public  boolean set(final String key,Object value){
            boolean result = false;
            try{
                redisTemplate.opsForValue().set(key,value);
                result = true;
            }catch (Exception e){
                e.printStackTrace();
            }
            return  result;
        }
}

service接口:IUserService

@Service
public interface IUserService {
	//根据id查用户信息
    User findById(int id);
}

UserService实现类:UserServiceImpl

@Service
public class UserServiceImpl implements IUserService {
    User user;
    @Autowired
    UserMapper userMapper;
    
    @Autowired
    private  RedisUtil redisUtil;

    @Override
    public User findById(int id) {
        String key = "user"+id;
        if(redisUtil.hasKey(key)) {
            user = (User)redisUtil.get(key);
            System.out.println("查询的是缓存");
        }else{
            user = userMapper.findById(id);
            System.out.println("查询的是数据库");
            System.out.println(redisUtil.set(key,user) ? "插入成功" : "插入失败");
        }
        return user;
    }
}

控制层UserController

@RestController
public class UserController {
    @Autowired
    IUserService userService;

    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Integer id){
        User user = userService.findById(id);
        return user;
    }
}

运行程序(redis记得处于开启状态)
访问 http://localhost:8080/user/1
在这里插入图片描述
查看redis
在这里插入图片描述
思路整理

第一步:创建项目,加入相关依赖web、mybatis、mysql、redis
第二步:配置文件,填mysql、redis的配置信息,创建数据库、表

第三步:写数据表对应的实体类、及mapper(sql语句)
第四步:创建一个redis的配置类(实现json转化)、工具类(判断缓存存在、插入、获取)
第五步:写一个服务接口及实现类

第六步:控制类

3、gradle项目管理工具

和maven差不多,是项目管理工具
gradle不像maven那样使用xml配置,它使用Groovy

3.1、用idea创建一个gradle项目

gradle下载地址:https://services.gradle.org/distributions/

下载完成后可以将bin文件夹配置到windows的系统变量path中

idea里面集成了gradle,所以可以不用下载。

用idea新建一个gradle项目
在这里插入图片描述
在这里插入图片描述
创建完成需要稍等一会才能创建完成(第一次创建是比较慢的)

gradle的目录结构和maven基本一样
在这里插入图片描述
jar依赖放在build.gradle里的dependencies里
在这里插入图片描述

3.2、build.gradle

gradle中行尾加不加分号都一样

在这里插入图片描述
repositories:指定仓库位置,mavenCentral()表示使用中央仓库

如下图表示先从本地仓库找依赖,没有再从中央仓库找

在这里插入图片描述

repositories {
    mavenLocal()
    mavenCentral()
}

怎么找到依赖呢

进入maven官网,找到我们需要的依赖

在这里插入图片描述
在这里插入图片描述

3.3、修改本地仓库位置

快速修改:在系统变量里添加GRADLE_USER_HOME,值为仓库位置

我们先找到它默认的本地项目地址
在这里插入图片描述
在这里插入图片描述
该目录下caches\modules-2\files-2.1就是仓库依赖位置,我们可以将整个caches都删了。

然后区系统变量里面配置一个GRADLE_USER_HOME,位置可以为maven的本地仓库位置
在这里插入图片描述
配置完重启idea,再打开settings里的gradle的仓库位置就变了
在这里插入图片描述

3.4、打包

在这里插入图片描述
jar包的位置
在这里插入图片描述

3.5、创建web项目

在这里插入图片描述
创建spring mvc项目:

其他的和创建web项目都一样,多下面这几个依赖

在这里插入图片描述
然后添加一下tomcat
在这里插入图片描述
在这里插入图片描述

4、java与jdk版本问题

Java10以前:

Java X=Java SE X=JDK1.X
例如java 8 = java SE 8 = jdk1.8。

Java10以后:

JDK对应名称为:JDK10、JDK11、JDK12、JDK13、JDK14

在这里插入图片描述

到目前Java 8 (也就是jdk1.8)依然是开发者最常用的版本。(2020年9月19日)

jdk :Java Development Kit (java开发工具集)

比较特殊的是这个工具集版本1.2 ~ 1.4 ,被称为 Java SDK (软件开发包, Software Development Kit )

JRE:Java Runtime Environment(Java运行环境),它包含虚拟机,但不包含编译器

JRE并不是开发者想要的环境, 而是专门为不需要编译器的用户而提供。

java SE:Java Standard Edition(java标准版本)

java EE:Java Enterprise Edition(java企业版)

Java ME:java Micro Edition(java微环境)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值