SpringBoot
SpringBoot是简化Spring应用开发的一个框架,对整个Spring技术栈的一个大整合,并且可以快速的创建生产级别的Spring应用,可以直接“运行”它们,应为内嵌入了Tomcat
创建基础项目说明
项目创建方式一:使用Spring Initializr 的 Web页面创建项目
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)方法
查看4道真题和解析

