SpringBoot

SpringBoot是简化Spring应用开发的一个框架,对整个Spring技术栈的一个大整合,并且可以快速的创建生产级别的Spring应用,可以直接“运行”它们,应为内嵌入了Tomcat

创建基础项目说明

项目创建方式一:使用Spring Initializr 的 Web页面创建项目

1、打开 https://start.spring.io/

2、填写项目信息

3、点击”Generate Project“按钮生成项目;下载此项目

4、解压项目包,并用IDEA以Maven项目导入,一路下一步即可,直到项目导入完毕。

5、如果是第一次使用,可能速度会比较慢,包比较多、需要耐心等待一切就绪。

项目创建方式二:使用 IDEA 直接创建项目

1、创建一个新项目

2、选择spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现
图片说明
3、填写项目信息
图片说明
4、选择初始化的组件(初学勾选 Web 即可,选择您要使用到的组件)
图片说明
5、填写项目路径

6、等待项目构建成功

配置端口

1、在application.yml中配置
图片说明

项目包规则

1、项目所有的包,要在主程序的同级目录下,一定要在同级目录下,否则识别不到
图片说明

编写

package org.david.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(){
        return "hello SpringBoot";
    }
}

图片说明

@RestController与@Controller的区别

  • @RestController:返回的是数据

    @RestController注解,相当于@Controller+@ResponseBody两个注解的结合,使用@RestController注解返回json数据不需要在方法前面加@ResponseBody注解了, 但使用@RestController这个注解,就不能返回jsp,html页面

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Controller
    @ResponseBody
    public @interface RestController {
      @AliasFor(
          annotation = Controller.class
      )
      String value() default "";
    }
  • @Controller:返回的是视图

这时候就有疑问了,那我到底是用@RestController这个注解,还是用@Controller这个注解,如果是前后端分离,就使用@RestController这个注解,后端返回数据,前端去得到后端返回的数据,达到前后端分离,如果不是前后端分,就使用@Controller这个注解

配置数据源

1、如果不配置数据源,他就会报错
图片说明

2、配置数据源

#配置数据源
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/smdms
    username: liao
    password: 123456

配置MyBatis

#配置MyBatis
mybatis:
  #配置MyBatis别名
  type-aliases-package: org.david.demo.pojo
  #Mapper 配置路径
  mapper-locations: classpath:mappers/*.xml

在主程序上开启@MapperScan注解

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//通过使用@MapperScan可以指定要扫描Mapper类包的路径,并生成相应的实现类(@MapperScan主要就是扫描得到mybatis的Mapper,并最终在Spring容器种初始化)
@MapperScan("org.david.demo.dao")
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

前后端分离

就是前端根据AJAX接受数据,后端返回JSON数据:如

package org.david.demo.controller;

import org.david.demo.pojo.User;
import org.david.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
public class UserController {
    @Resource
    private UserService userService;

    @GetMapping("/get/{id}")
    public User get(@PathVariable int id){
        User user=userService.getSingle(id);
        return user;
    }
}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="jquery-1.8.3.min.js"></script>
</head>
<body>
    <div id="info"></div>
    <button id="load">加载数据</button>
</body>
<script>
    $(function () {
       $("#load").click(function () {
          $.ajax({
             //要写上完整的地址
             url:"http://localhost:8000/get/1",
             dataType:"json",
             success:function (data) {
                 $("#info").html(data.userCode+"\t"+data.userPassword);
             }
          });
       });
    });
</script>
</html>

后端要放开限制,容许前端访问,有2种分为:局部,全局
不然会报错
图片说明
图片说明
图片说明
局部设置:在每个Controller上添加@CrossOrigin注解,但是只作用在当前Controller中,所以要设置全局作用

package org.david.demo.controller;

import org.david.demo.pojo.User;
import org.david.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;
@CrossOrigin
@RestController
public class UserController {
    @Resource
    private UserService userService;

    @GetMapping("/get/{id}")
    public User get(@PathVariable int id){
        User user=userService.getSingle(id);
        return user;
    }
}

全局设置:让主程序继承WebMvcConfigurationSupport,然后重写addCorsMappings

package org.david.demo;

import com.sun.nio.sctp.PeerAddressChangeNotification;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

//通过使用@MapperScan可以指定要扫描Mapper类包的路径,并生成相应的实现类(@MapperScan主要就是扫描得到mybatis的Mapper,并最终在Spring容器种初始化)
@MapperScan("org.david.demo.dao")
@SpringBootApplication
public class DemoApplication extends WebMvcConfigurationSupport {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    protected void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

这时前端就可以访问后端数据了
图片说明
前后端分离就是多个项目如:一个只存放后端代码,一个只存放前端代码,然后根据AJAX想连,一个发送数据,一个得到数据

日期问题

  # 设置JSON的日期格式
  jackson:
    date-format: yyyy-MM-dd
  # 设置上传的日期格式
  mvc:
    date-format: yyyy-MM-dd

但是不会生效为什么,应为主程序类继承了一个WebMvcConfigurationSupport配置类,这个配置类中有一个addFormatters方法主要作用是用于增加转化器或者格式化器是一个空实现,所以不实现格式化,继承WebMvcConfigurationSupport配置类,要实现格式化,就要对他进行重写

    protected void addFormatters(FormatterRegistry registry) {
    }

但是不继承WebMvcConfigurationSupport配置类,重写addCorsMappings就有前端访问的问题,这时就可以使用自定义配置类,去实现WebMvcConfigurer 接口,实现你要的方法,加上@Configuration注解,然后主程序类就去继承自定义配置类

package org.david.demo.config;

import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}
package org.david.demo;

import com.sun.nio.sctp.PeerAddressChangeNotification;
import org.david.demo.config.CorsConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

//通过使用@MapperScan可以指定要扫描Mapper类包的路径,并生成相应的实现类(@MapperScan主要就是扫描得到mybatis的Mapper,并最终在Spring容器种初始化)
@MapperScan("org.david.demo.dao")
@SpringBootApplication
public class DemoApplication extends CorsConfig {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

文件上传

跟Spring一样,但是SpringBoot不需要配置上传组件,SpringBoot已经帮你加载了上传组件,
图片说明

    @PostMapping("/add")
    public Map<String,Object> getAdd(User user, MultipartFile file) throws IOException {
        if (!file.isEmpty()){
            file.transferTo(new File("F:/文件"+user.getUserCode()+".jsp"));
        }
        Map<String,Object> map=new HashMap<>();
        int insert = userService.insert(user);
        map.put("count",insert);
        return map;
    }
    $(function () {
            $("#seve").click(function () {
                //它是为序列化表表单以及创建与表单格式相同的数据,提供传输便利。
                //使用FormData将表单元素转为键值对,他是原生js不能使用Jquery获取表单对象
                var form=new FormData($("form")[0]);
                $.ajax({
                    url:"http://localhost:8000/add",
                    type:"post",
                    dataType:"json",
                    data:form,
                    /**
                     contentType:发送数据的格式
                     和 contentType 有个类似的属性是 dataType , 代表的是期望从后端收到的数据的格式,一般会有 json 、text……等
                     而 contentType 则是与 dataType 相对应的,其代表的是 前端发送数据的格式

                     默认值:application/x-www-form-urlencoded
                     代表的是 ajax 的 data 是以字符串的形式 如 id=2019&password=123456
                     使用这种传数据的格式,无法传输复杂的数据,比如多维数组、文件等

                     有时候要注意,自己所传输的数据格式和ajax的contentType格式是否一致,如果不一致就要想办法对数据进行转换
                     把contentType 改成 false 就会改掉之前默认的数据格式,在上传文件时就不会报错了。
                     */
                    contentType:false,
                    //processData:处理数据
                    //默认情况下,processData 的值是 true,其代表以对象的形式上传的数据都会被转换为字符串的形式上传。而当上传文件的时候,则不需要把其转换为字符串,因此要改成false
                    processData:false,
                    success:function (data) {
                        if (data.count>0){
                            alert("上传成功");
                        }else {
                            alert("上传失败");
                        }
                    }
                });
            });

}

使用FormData 将表单元素转为键值对数据,他是原生js不能使用Jquery获取表单对象
图片说明
图片说明

@Configuration

@Configuration 用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

注册Baen

随着SpringBoot的流行,基于注解式开发的热潮逐渐覆盖了基于XML纯配置的开发,而作为Spring中最核心的bean当然也能够使用注解的方式进行表示

package org.david.demo.config;

import org.david.demo.pojo.People;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
    /**
     *使用@Bean 注解表明people需要交给Spring进行管理
     *未指定bean 的名称,默认采用的是 "方法名" + "首字母小写"的配置方式
     * @Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用为:注册bean对象
     *
     * @return
     */
    @Bean
    public People people(){
        People people=new People();
        //注入属性
        people.setName("KK");
        people.setAge(24);
        people.setGender("男");
        return people;
    }
}
package org.david.demo;

import com.sun.nio.sctp.PeerAddressChangeNotification;
import org.david.demo.config.CorsConfig;
import org.david.demo.pojo.People;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

//通过使用@MapperScan可以指定要扫描Mapper类包的路径,并生成相应的实现类(@MapperScan主要就是扫描得到mybatis的Mapper,并最终在Spring容器种初始化)
@MapperScan("org.david.demo.dao")
@SpringBootApplication
public class DemoApplication extends CorsConfig {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
       /* String[] beanDefinitionNames = run.getBeanDefinitionNames();
        for (String name:beanDefinitionNames){
            System.out.println(name);
        }*/
       //获取Bean
       People people=run.getBean(People.class);
       System.out.println(people);
    }
}

图片说明
但是这种注入属性不过灵活,建议使用配置文件yml,要在实体类上添加@ConfigurationProperties映射
通过注解@ConfigurationProperties(prefix="配置文件中的key的前缀")可以将配置文件中的配置自动与实体进行映射

package org.david.demo.pojo;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@ConfigurationProperties("people")
public class People {
    private String name;
    private int age;
    private String gender;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    ....

图片说明
注意:使用@ConfigurationProperties方式可以进行配置文件与实体字段的自动映射,但需要字段必须提供set方法才可以,而使用@Value注解修饰的字段不需要提供set方法

Redis

我们目前的系统已经实现了广告后台管理和广告前台展示,但是对于首页每天有大量的人访问,对数据库造成很大的访问压力,甚至是瘫痪。那如何解决呢?我们通常的做法有两种:一种是数据缓存、一种是网页静态化。我们今天讨论第一种解决方案。

redis 是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写。企业开发通常采用Redis来实现缓存。同类的产品还有memcache 、memcached 、MongoDB等。

Redis应用场景

1.热点数据加速查询(主要场景),如热点商品、热点信息等访问量较高的数据
2.即时信息查询,如公交到站信息、在线人数信息等
3.时效性信息控制,如验证码控制、投票控制等
4.分布式数据共享,如分布式集群架构中的session分离消息队列

数据结构介绍

Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)
图片说明
注意:Redis采用键值对存储数据,key永远是String类型,五大数据类型指的是value部分

SpringBoot中使用Redis

添加Redis场景依然

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

编写Redis操作工具类

将RedisTemplate实例包装成一个工具类,便于对redis进行数据操作

package org.david.demo.tools;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {
    @Resource
    RedisTemplate<String,Object> redisTemplate;

    /**
     * 添加
     * @param key
     * @param value
     */
    public void set(String key,Object value){
        //opsForValue:用于操作简单的数据类型
        //opsForSet:用于操作set类型数据
        //opsForHash:用于操作Map类型数据
        //opsForList:用于操作liast类型数据
        redisTemplate.opsForValue().set(key,value);
    }

    //set还可以设置变量值的过期时间,TimeUnit设置时间类型:TimeUnit.DAYS 天 TimeUnit.HOURS 小时
    public void set(String key,Object value,long timeout){
        redisTemplate.opsForValue().set(key,value,timeout, TimeUnit.HOURS);
    }

    /**
     * 获取
     * @param key
     * @return
     */
    public Object get(String key){
       return redisTemplate.opsForValue().get(key);
    }

    /**
     * 根据key删除reids中缓存数据
     * @param key
     * @return
     */
    public boolean delete(String key){
        return redisTemplate.delete(key);
    }

    /**
     * 更新
     * 获取原来key键对应的值并重新赋新值。
     * @param key
     * @param value
     */
    public void  getAndSet(String key, Object value){
        redisTemplate.opsForValue().getAndSet(key,value);
    }

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

    /**
     *重新设置过期时间
     * @param key
     * @param timeout
     */
    public void expire(String key,long timeout){
        redisTemplate.expire(key,timeout,TimeUnit.HOURS);
    }

}

RedisTemplate的Bean

你可以使用SpringBoot创建的Bean,也可以自己创建一个RedisTemplate的Bean

    //SpringBoot创建的Bean
    @Bean
    @ConditionalOnMissingBean(name = {"redisTemplate"})
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
package org.david.demo.config;

import org.david.demo.pojo.People;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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 java.net.UnknownHostException;

@Configuration
public class BeanConfig {
    /**
     * 我们可以自定义一个RedisTemplateBean来替换默认的Bean
     * @param redisConnectionFactory
     * @return
     * @throws UnknownHostException
     */
    @Bean
    @ConditionalOnMissingBean(name = {"redisTemplate"})
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

自定义视图信息对象

package org.david.demo.pojo;

public class view<T> {
    /**
     * 返回的类型
     */
    private T data;
    /**
     * 状态码
     */
    private int code;
    /**
     * 成功信息
     */
    private String message;
    /**
     * 失败信息
     */
    private String error;

    public view(T data, int code, String message, String error) {
        this.data = data;
        this.code = code;
        this.message = message;
        this.error = error;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }
}

测试

package org.david.demo.controller;

import org.david.demo.pojo.User;
import org.david.demo.pojo.view;
import org.david.demo.service.UserService;
import org.david.demo.tools.RedisUtil;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@CrossOrigin
@RestController
public class UserController {
    @Resource
    private UserService userService;

    @Resource
    private RedisUtil redisUtil;

    @PostMapping("/login")
    public view login(String userCode, String userPassword, HttpServletResponse response){
        User login = userService.login(userCode, userPassword);
        if (login!=null){
            redisUtil.set(login.getUserCode(),login);
            Cookie cookie=new Cookie("token",login.getUserCode());
            response.addCookie(cookie);
        }
        view<User> view=new view<>(login,login==null?520:200,login==null?"用户名或密码错误":"登录成功",login==null?"用户名或密码错误":null);
        return view;
    }
}

图片说明
图片说明

控制器

控制器写法根Spring一样,去实现HandlerInterceptor接口,在重写preHandle方法,如:验证是否登录代码如下

package org.david.demo.filter;

import org.david.demo.tools.RedisUtil;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SysInterceptor implements HandlerInterceptor {
    @Resource
    private RedisUtil redisUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Cookie[] cookies = request.getCookies();
        //判断是否为空,不为空进入
        if (cookies!=null){
            //循环Cookie
            for (Cookie cookie:cookies){
                //得到key
                String name = cookie.getName();
                //判断是否有token的key
                if (name.equals("token")){
                    //得到值,并判断Redis是否有key
                    if (redisUtil.hasKey(cookie.getValue())){
                        return true;
                    }
                }
            }
        }
        //若没有登录跳转至/nologin
        request.getRequestDispatcher("/nologin").forward(request,response);
        return false;
    }
}

然后注册控制器,实现 WebMvcConfigurer 接口重写其addInterceptors(InterceptorRegistry registry)方法

全部评论

相关推荐

11-05 07:29
贵州大学 Java
点赞 评论 收藏
分享
1 1 评论
分享
牛客网
牛客企业服务