Springboot(编程不良人)
Springboot(编程不良人)
文章目录
- Springboot(编程不良人)
- 1、SpringbootApplication注解相关说明
- 2、配置文件拆分以及加载外部配置文件
- 3、管理对象的创建
- 3.1、创建单个对象
- 3.2、创建多个对象
- 4、属性注入
- 1、@Value注解进行属性注入
- 2、以对象的形式注入
- 5、整合mybatis思路分析
- 5.1、回顾spring框架如何整合mybatis
- 5.2、springboot框架如何整合mybatis
- 6、@Mapper注解和@MapperScan接口的区别
- 7、本地测试
- 7.1、spring中的本地测试
- 7.2、Springboot框架中完成本地测试
- 8、日志处理
- 8.1、日志的级别
- 8.2、日志的配置
- 9、ems-jsp简单入门案例
- 9.1、项目开发流程
- 9.2、项目实例
- 9.2.1、准备部分+环境搭建
- 9.2.2、注册部分知识点
- 9.2.3、登录部分知识点
- 9.2.4、员工列表部分
- 9.2.5、添加员工部分
- 9.2.6、更新员工部分
- 10、面向切面编程AOP
- 10.1、spring框架的AOP回顾
- 10.2、springboot框架AOP
- 10.3、注解内的表达式
- 10.3.1、方法级别:
- 10.3.2、包级别:
- 10.3.2、注解级别:
- 11、文件上传
- 11.1、Springboot上传文件要点
- 12、文件下载
- 12.1、文件下载的步骤
- 12.2、文件下载的步骤
- 13、拦截器
- 13.1、过滤器的介绍
- 13.2、拦截器的作用
- 13.3、拦截器的特性
- 13.4、用法介绍
- 13.5、例子
- 14、springboot部署方式
- 14.1、war部署
- 14.2、jar包部署(一般前后端分离项目)
- 15、Restful API
- 15.1、使用restful操作资源
- 15.2、Restful风格测试
- 15.3、restful标准返回类型和状态码
- 16、异常处理
- 16.1、传统web项目的异常处理
- 16.2、前后端分离项目的异常处理
- 17、CORS
1、SpringbootApplication注解相关说明
该注解是一个只能作用在类上组合注解(由@SpringBootConfiguration和@EnableAutoConfiguration和@ComponentScan)
其中@Target(指定注解作用范围)、@Retention(指定注解什么时候有效)、@Doucumented、@Inherited四个注解为java自带的元注解:只能修饰注解的注解。
@SpringBootConfiguration:这个注解就是用来自动配置spring、springmvc(初始化servlet。。。)相关环境
@EnableAutoConfiguration:开启自动配置,自动配置spring相关环境,引入第三方技术自动配置环境(mybatis-springboot、redis-springboot等第三方技术)
ComponentScan:组件扫描 根据注解发挥注解作用,默认扫描当前包以及其子包
2、配置文件拆分以及加载外部配置文件
平时我们的生产环境配置和开发环境配置一般不同,如何在springboot的配置文件中更换不同环境的配置文件
方法一
1、通过application-XXX.yml命名作为其他环境配置
2、在application.yml中更换配置环境
测试
1.通过application.yml进行公共配置
2.创建开发环境application-dev.yml
3.创建开发环境application-prod.yml
3.在application.yml设置开启的环境配置
4、访问hello请求
方法二 调用外部的配置文件
修改启动程序的参数
–spring.config.location=外部配置文件的绝对地址
3、管理对象的创建
3.1、创建单个对象
在springboot中管理单个对象课直接使用spring框架中注解形式创建
- @Component 通过注解创建对象
- Controller 用来创建控制器对象
- Service 用来创建业务层对象
- Repository 用来创建Dao层对象
- 以上注解都有value属性,value属性用来指定工厂终对象的名称
例子:
1、service包中的DemoService接口
public interface DemoService {public void Demo();
}
2.service包中的DemoServiceImpl类
@Service
public class DemoServiceImpl implements DemoService{@Overridepublic void Demo() {System.out.println("Demo()方法");}
}
3、controller包中的DemoController
@RestController
public class DemoController {@Autowiredprivate DemoService demoService;@RequestMapping("/demo")public String demo(){demoService.Demo();return "demo ok";}
}
3.2、创建多个对象
如何在springboot中像spring框架一样通过xml创建对个对象,在springboot中也提供了相同的注解,如:
@Configuration、@Bean
- @Configuration:代表这是一个spring的配置类,相当于spring.xml配置文件
- @Bean:用来在工厂中创建这个@Bean注解表示对象
- 默认使用@Bean创建对象在工厂中唯一标识为方法名称
- 修改在工厂中对象标识可以使用@Bean(“工程中的名字”)指定一个名字
例子:
1.在config包下创建BeanConfig类
@Configuration//注解表名这是一个配置类,相当于spring中的spring.xml
public class BeanConfig {@Bean//注入Calendar类型的对象,名字与方法名相同public Calendar calendar(){return Calendar.getInstance();}
}
2、controller层测试
@RestController
public class DemoController {@Autowiredprivate DemoService demoServiceImpl;@Autowiredprivate Calendar calendar;@RequestMapping("/demo")public String demo(){demoServiceImpl.Demo();System.out.println("日期:"+calendar.getTime());return "demo ok";}
}
4、属性注入
1、@Value注解进行属性注入
引用类型:@Autowried
8中基本类型,String,数组、list、map
例子:
1、appliacation.yml
name: 小莫
age: 21
birthday: 2000/12/12 12:12:12 #java中默认的日期格式是:yyyy/mm/dd HH:MM:ss
sex: false
qqs: 1,2,3,4 #注入数组时,多个元素用','隔开
lists: morant,more,lirmood #注入list时,多个元素用,隔开,和数组一样
maps: "{'name':'morant','age':'21'}" #json字符串的形式
2、injectController
@RestController
public class injectController {@Value("${name}")private String name;@Value("${age}")private int age;@Value("${birthday}")private Date birthday;@Value("${sex}")private boolean sex;@Value("${qqs}")private int[] qqs;@Value("${lists}")private List<String> lists;@Value("#{${maps}}")//在注入map集合时,配置文件要是用json格式赋值 在注入式必须使用@{#{${}}}进行注入private Map<String,String> maps;@RequestMapping("/inject")public String inject(){System.out.println("name = " + name);System.out.println("age = " + age);System.out.println("birthday = " + birthday);System.out.println("sex = " + sex);System.out.println("=================");System.out.println("数组遍历");for (int qq : qqs) {System.out.println("qq = " + qq);}System.out.println("=================");System.out.println("list遍历");lists.forEach(li-> System.out.println("li = " + li));System.out.println("=================");System.out.println("map遍历");maps.forEach((key,value)-> System.out.println("key = " + key+" value = "+ value));return "inject ok";}
}
2、以对象的形式注入
@ConfigurationProperties:
/**
*作用范围:作用在类上
* 作用:用来指定配置文件中前缀的属性 注入到当前对象中属性一致的属性中
* 注意:必须要有get和set方法
*/
例子:
1、application.yml文件
order:id: 19100116age: 21
2、inject2Controller(一定要有get和set方法,一定要是用@ConfigurationProperties注解)
@RestController
/*** 作用范围:作用在类上* 作用:用来指定配置文件中前缀的属性 注入到当前对象中属性一致的属性中* 注意:必须要有get和set方法*/@ConfigurationProperties(prefix = "order")
public class inject2Controller {private String id;private String age;@RequestMapping("/inject2")public String inject2(){System.out.println(id);System.out.println(age);return "inject2 OK";}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}
}
5、整合mybatis思路分析
5.1、回顾spring框架如何整合mybatis
1.引入依赖
- spring相关
- mysql相关 驱动 数据源
- mybatis相关 mybatis核心jar mybatis和spring框架整合
2。spring.xml
- 开启注解扫描
- 创建数据源对象
- 注入 指定使用哪种数据源类型 注入diverClassName 注入url、username、password
- 创建sqlSessionFactory
- 注入 数据源 注入mapper配置文件位置 注入实体别名包
- 创建Dao对象
- 注入SqlSessionFactory 以及Dao接口所在包
- 创建事务管理器 DataSourceTranacationManager
- 注入数据源对象
- 在业务层组件上加入事务注解 @Transacational
3.测试
5.2、springboot框架如何整合mybatis
1.引入依赖
- spring-web
- mysql相关 mysql驱动 druid数据源
- mybatis相关(mybatis-spring-boot-stater)依赖
2.书写配置
- 开启注解扫描 @SpringBootApplication @ComponentScan可以省略
- 创建数据源
- 注定数据源类型
- 指定数据库驱动
- 指定url
- 指定username
- 指定password
- 创建SqlSessionFactory
- 指定mapper配置文件的位置
- 指定实体所在的包的位置 起别名
- 创建Dao
- 指定Dao接口所在的包
3.测试
例子
1、导入依赖
<!--导入数据源 druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.4</version></dependency><!--导入数据库驱动 mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!--导入mybatis-springboot-starter 包含mybatis和mybatis-spring--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency>
2、修改配置文件 application-yml
server:port: 8989servlet:context-path: /springboot-mybatis
#整合mybatis相关配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverpassword: 123456username: rooturl: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
#mybatis相关配置设置之后 才会创建SqlSessionFcatory
mybatis:type-aliases-package: com.morant.entity #指定实体类的包名,默认别名:类名或者类名的首字母小写mapper-locations: classpath:com/morant/mapper/*.xml #指定mapper配置文件的位置#在主类中指定dao接口所在的包
3、在主类中指定dao接口所在的包
@SpringBootApplication
@MapperScan("com.morant.dao")//修饰范围:用在类上 作用:用来扫描dao接口所在的包 同时将所有dao接口在工厂中创建代理对象
public class SpringBootMybatisApplication {public static void main(String[] args) {SpringApplication.run(SpringBootMybatisApplication.class, args);}}
4、测试
4.1、创建数据库
4.2、创建实体类User
public class User {private int id;private String name;private String password;public User(int id, String name, String password) {this.id = id;this.name = name;this.password = password;}public User() {}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
4.3、创建Userdao接口
public interface UserDao {public List<User> findall();
}
4.4、在创建UserDaoMapper配置文件
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.morant.dao.UserDao"><select id="findall" resultType="user">select id,name,password from `user`</select></mapper>
4.5、创建UserService接口
public interface UserService {public List<User> findall();
}
4.6、创建UserServiceImpl实现类
@Service
@Transactional
public class UserServiceImpl implements UserService{private UserDao userDao;@Autowiredpublic UserServiceImpl(UserDao userDao) {//这里报错没关系,因为Dao还没被主类扫描进来,或者在Dao上加@Mapperthis.userDao = userDao;}public List<User> findall(){return userDao.findall();};
}
4.7创建UserController
6、@Mapper注解和@MapperScan接口的区别
@Mapper:添加在Dao接口上,在工厂中创建代理对象,但是一次只能作用一个Dao接口,相对麻烦
7、本地测试
7.1、spring中的本地测试
1、启动工厂
ApplicationCpntext context = new ClassPathXmlApplicationContext("spring.xml")
2、从工厂中获得指定对象
UserDao userDao = context.getBean("UserDao")
3、调用方法
useDao.xxx(参数)
7.2、Springboot框架中完成本地测试
1.引入结合junit和springboot的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
- 启动springboot应用才能启动工厂 注入测试对象
@SpringBootTest
作用范围:在类上
作用:在这个类实例化过程中启动springboot应用
8、日志处理
springboot框架集成日志logback日志
8.1、日志的级别
ALL:最低等级的,用于打开所有日志记录。
TRACE:很低的日志级别,一般不会使用。
DEBUG: 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
INFO: 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
WARN: 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
ERROR: 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
FATAL: 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
OFF: 最高等级的,用于关闭所有日志记录。
8.2、日志的配置
#配置日志
logging:level:root: info #全局日志com.morant.service: debug #指定包的日志file:name: run.log #输出日志文件的名字path: ./ #将日志文件生成在本项目下
调试时输出日志
@Service
@Transactional
public class UserServiceImpl implements UserService{private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);private UserDao userDao;@Autowiredpublic UserServiceImpl(UserDao userDao) {this.userDao = userDao;}public List<User> findall(){log.debug("查询完毕");return userDao.findall();};
}
注意
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); 这个注解
9、ems-jsp简单入门案例
9.1、项目开发流程
- 需求分析:分析用户主要需求,提取出项目的核心功能,根据核心功能构建页面原型
- 库表设计(概要设计):1.分析系统有哪些表,2.分析出表之间的关系,3.确定字段
- 详细设计(流程图、伪代码):用来验证库表设计的准确性
- 功能实现(编码):环境搭建 具体功能时间
- 部署
- 上线
- 运维
9.2、项目实例
9.2.1、准备部分+环境搭建
1、创建ems-jsp的springboot项目
2、修改properties为yml,在main
下面新建一个webapp(存放jsp)
3、导入依赖
<!-- 开启jsp解析依赖--><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><!-- 开启springboot热部署调试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.4</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!-- mybatis-spring-boot-stater--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency>
3、项目配置
server:port: 8989 #指定端口servlet:context-path: /ems-jsp #指定项目名jsp:init-parameters:development: true #开启jsp模板的开发模式#配置jsp解析模板和数据库
spring:mvc:view:prefix: /suffix: .jspdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8#配置mybatis
mybatis:mapper-locations: classpath:com/morant/mapper/*.xmltype-aliases-package: com.morant.entity#主入口加一个@MapperScan#配置日志的使用
logging:level:root: infocom.morant: debug #指定包日志
5、创建数据库表
9.2.2、注册部分知识点
1.验证码生成工具VarifyCodeUtils
package com.morant.utils;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;/*** 验证码工具类* 使用到Algerian字体,系统里没有的话需要安装字体**/
public class VerifyCodeUtils {// 字体只显示大写,去掉了1,0,i,o几个容易混淆的字符public static final String VERIFY_CODES = "23456789abcdefghgkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";private static Random random = new Random();/*** 使用系统默认字符源生成验证码** @param verifySize 验证码长度* @return*/public static String generateVerifyCode(int verifySize) {return generateVerifyCode(verifySize, VERIFY_CODES);}/*** 使用指定源生成验证码** @param verifySize 验证码长度* @param sources 验证码字符源* @return*/public static String generateVerifyCode(int verifySize, String sources) {if (sources == null || sources.length() == 0) {sources = VERIFY_CODES;}int codesLen = sources.length();Random rand = new Random(System.currentTimeMillis());StringBuilder verifyCode = new StringBuilder(verifySize);for (int i = 0; i < verifySize; i++) {verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));}return verifyCode.toString();}/*** 生成随机验证码文件,并返回验证码值** @param w* @param h* @param outputFile* @param verifySize* @return* @throws IOException*/public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {String verifyCode = generateVerifyCode(verifySize);outputImage(w, h, outputFile, verifyCode);return verifyCode;}/*** 输出随机验证码图片流,并返回验证码值** @param w* @param h* @param os* @param verifySize* @return* @throws IOException*/public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException {String verifyCode = generateVerifyCode(verifySize);outputImage(w, h, os, verifyCode);return verifyCode;}/*** 生成指定验证码图像文件** @param w* @param h* @param outputFile* @param code* @throws IOException*/public static void outputImage(int w, int h, File outputFile, String code) throws IOException {if (outputFile == null) {return;}File dir = outputFile.getParentFile();if (!dir.exists()) {dir.mkdirs();}try {outputFile.createNewFile();FileOutputStream fos = new FileOutputStream(outputFile);outputImage(w, h, fos, code);fos.close();} catch (IOException e) {throw e;}}/*** 输出指定验证码图片流** @param w* @param h* @param os* @param code* @throws IOException*/public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {int verifySize = code.length();BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);Random rand = new Random();Graphics2D g2 = image.createGraphics();g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);Color[] colors = new Color[5];//Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW };Color[] colorSpaces = new Color[] { Color.WHITE, Color.blue, Color.GRAY, Color.RED, Color.GREEN, Color.ORANGE, Color.CYAN, Color.YELLOW };float[] fractions = new float[colors.length];for (int i = 0; i < colors.length; i++) {colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];fractions[i] = rand.nextFloat();}Arrays.sort(fractions);g2.setColor(Color.RED);// 设置边框色g2.fillRect(0, 0, w, h);Color c = getRandColor(200, 250);g2.setColor(c);// 设置背景色g2.fillRect(0, 2, w, h - 4);// 绘制干扰线Random random = new Random();//g2.setColor(getRandColor(160, 200));// 设置线条的颜色g2.setColor(getRandColor(100, 255));// 设置线条的颜色for (int i = 0; i < 20; i++) {int x = random.nextInt(w - 1);int y = random.nextInt(h - 1);int xl = random.nextInt(6) + 1;int yl = random.nextInt(12) + 1;g2.drawLine(x, y, x + xl + 40, y + yl + 20);}// 添加噪点// 噪声率float yawpRate = 0.02f;int area = (int) (yawpRate * w * h);for (int i = 0; i < area; i++) {int x = random.nextInt(w);int y = random.nextInt(h);int rgb = getRandomIntColor();image.setRGB(x, y, rgb);}
// 使图片扭曲shear(g2, w, h, c);//g2.setColor(getRandColor(100, 160));g2.setColor(getRandColor(100, 255));int fontSize = h - 4;Font font = new Font("Algerian", Font.ITALIC, fontSize);g2.setFont(font);char[] chars = code.toCharArray();for (int i = 0; i < verifySize; i++) {AffineTransform affine = new AffineTransform();affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);g2.setTransform(affine);g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);}g2.dispose();ImageIO.write(image, "jpg", os);}private static Color getRandColor(int fc, int bc) {if (fc > 255){fc = 255;}if (bc > 255){bc = 255;}int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}private static int getRandomIntColor() {int[] rgb = getRandomRgb();int color = 0;for (int c : rgb) {color = color << 8;color = color | c;}return color;}private static int[] getRandomRgb() {int[] rgb = new int[3];for (int i = 0; i < 3; i++) {rgb[i] = random.nextInt(255);}return rgb;}private static void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}private static void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}private static void shearY(Graphics g, int w1, int h1, Color color) {// 50int period = random.nextInt(40) + 10;boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}
}
2、验证码实现Controller
@RequestMapping("/generateImageCode")public void find(HttpSession session, HttpServletResponse response) throws IOException {//1.生成随机验证码String code = VerifyCodeUtils.generateVerifyCode(4);//2.保存随机字符串到session中session.setAttribute("code",code);//3.将随机字符串生成图片//4.通过response响应图片ServletOutputStream os = response.getOutputStream();VerifyCodeUtils.outputImage(120,60,os,code);}
3、密码加密,用java提供的DigestUtils
@Overridepublic void register(User user) {//1.根据数据库查询书否存在该用户名User userDB = userDao.findByUserName(user.getUsername());//2.如果存在 报错if(!ObjectUtils.isEmpty(userDB))throw new RuntimeException("用户名已存在");//3.如果不存在,就注册,注册前给密码加密String passwordSecret = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));user.setPassword(passwordSecret);userDao.save(user);}
4、传回错误信息值前端,需要设置字符格式,用到URLEncoder类,需要设置UTF-8
@RequestMapping("/register")public String register(HttpSession session,User user,String code) throws UnsupportedEncodingException {log.debug("用户名{},真实姓名{},密码{},性别{},验证码{}",user.getUsername(),user.getRealname(),user.getPassword(),user.getGender(),code);String sessionCode = session.getAttribute("code").toString();//判断验证码是否正确try {if(!(sessionCode.equalsIgnoreCase(code)))throw new RuntimeException("验证码错误");//验证码正确,调用UseService接口进行注册userService.register(user);} catch (RuntimeException e) {e.printStackTrace();return "redirect:/regist.jsp?msg="+ URLEncoder.encode(e.getMessage(),"UTF-8");}return "redirect:/login.jsp";}
9.2.3、登录部分知识点
主要登录成功之后需要将账号存入session
@RequestMapping("/login")public String login(HttpSession session,String username,String password) throws UnsupportedEncodingException {log.debug("接收到的用户名{},接受到的密码{}",username,password);try {User user = userService.login(username,password);session.setAttribute("user",user);} catch (Exception e) {e.printStackTrace();return "redirect:/login.jsp?msg="+URLEncoder.encode(e.getMessage(),"UTF-8");}return "emplist";}
9.2.4、员工列表部分
1、前端使用c标签需要导包
<!-- jstl c标签库,标准标签库-->
<dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version>
</dependency>
2、c-foreach标签的使用
<c:forEach items="${requestScope.employee}" var="employee"><tr><td>${employee.id}</td><td>${employee.name}</td><td>${employee.birthday}</td><td>${employee.salary}</td><td>${employee.gender?"男":"女"}</td><td><a href="javascript:void(0)">更新</a><a href="javascript:;">删除</a></td></tr>
</c:forEach>
3、HttpServletRequest的request和Model类型model添加属性都是添加到requestScop中。等价
@RequestMapping("/list")public String list(HttpServletRequest request, Model model){List<Employee> employee = employeeService.list();// request.setAttribute("employee",employee);// 上面的是servlet原始提供的一种存入数据到request域的方法等价于下面的方法model.addAttribute("employee",employee);return "emplist";}
4、要跳转请求使用redirect
5、前端引入的css前面的路径需要用${pageContext.request.contextPath}
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
9.2.5、添加员工部分
1、添加部分的主键自增设计 keyProperty=“id” useGeneratedKeys="true"
<insert id="add" parameterType="employee" keyProperty="id" useGeneratedKeys="true">insert into `employee` values (#{id},#{name},#{birthday},#{salary},#{gender})
</insert>
**2、默认java默认日期格式 **
java、Spring、springmvc默认的日期格式为 yyyy/MM/dd HH:mm:ss
//java spring springmvc默认的日期格式为 yyyy/MM/dd HH:mm:ss 除非用 @DateTimeFormat(pattern="")修改
@DateTimeFormat(pattern = "yyyy-MM-dd")
9.2.6、更新员工部分
1、更新员工应该先通过员工的id去查找该员工并回显(在url后面拼接id)
<a href="${pageContext.request.contextPath}/employee/detail?id=${employee.id}">更新</a>
2、根据回显的信息进行修改之后 在去数据库中修改,id也要回显
10、面向切面编程AOP
10.1、spring框架的AOP回顾
AOP:Aspect(切面) Oriented(面向) programming面向切面别称
Ascept(切面) = Advice(通知) + 切入点(prointcut)
Advice 通知:业务逻辑中一些附加操作成为通知,分为前置操作、后置操作、环绕操作
Point切入点:配置通知应用于项目中的哪些业务操作
Aspect切面=附加操作(Advice)+ 切入点(pointcut)
步骤:
1、类 implements xxAdvice接口
2、xml进行配置
<aop:config><aop:ppintcut id="pc" expression="execution(*包.类.方法名(方法参数))|within(类级别)|annotation(注解类型)"/><aop:advisor advice-ref="通知类" pointcut-ref="pc"/>
</aop:config>
10.2、springboot框架AOP
无xml配置,一切皆java配置
步骤:
1、引入aop切面编程依赖
<!-- 引入aop支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
2、在spring醒目包中新建config(配置包)
/*** 自定义切面配置类*/
@Configuration//告诉springboot这是一个配置类
@Aspect//代表这是一个切面配置类
public class MyAspectConfig {//切面aspect=advice + pointcut@Before("execution(* com.morant.service.*.*(..))")//代表这是一个核心业务逻辑执行前的前置通知 value用来书写切入点表达式public void before(JoinPoint joinPoint){System.out.println("======调用前置通知========");System.out.println(joinPoint.getTarget());System.out.println(joinPoint.getStaticPart().getSignature().getName());}//切面aspect=advice + pointcut@After("execution(* com.morant.service.*.*(..))")//代表这是一个核心业务逻辑执行前的前置通知 value用来书写切入点表达式public void after(JoinPoint joinPoint){System.out.println("======调用后置通知======");System.out.println(joinPoint.getTarget());System.out.println(joinPoint.getStaticPart().getSignature().getName());}@Around("execution(* com.morant.service.*.*(..))")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("======环绕放行前======");//放行Object proceed = proceedingJoinPoint.proceed();System.out.println("======环绕放行后======");return proceed;}
}
3、service包中的接口和类
public interface UserService {void show();void delete();String find();
}
@Service
public class UserServiceImpl implements UserService {@Overridepublic void show() {System.out.println("调用了Dao的show方法");}@Overridepublic void delete() {System.out.println("调用了Dao的delete方法");}@Overridepublic String find() {return "小明";}
}
总结!!!
//注解:
@Configuration:告诉springboot这是一个配置类
@Aspect:代表这是一个切面配置类
@Before("execution(* com.morant.service.*.*(..))"):代表这是一个核心业务逻辑执行前的前置通知 value用来书写切入点表达式
@After("execution(* com.morant.service.*.*(..))"):代表这是一个核心业务逻辑执行后的后置通知 value用来书写切入点表达式
@Around("execution(* com.morant.service.*.*(..))"):代表这是一个环绕同志 value用来书写切入点表达式其中
@Before
@After
这两个注解的方法中可以使用JoinPoint连接点类作为参数,可以获得业务逻辑的类名和方法名
获得类名:joinPoint.getTarget()
获得方法名:joinPoint.getStaticPart().getSignature().getName()而@Around
需要proceedingJoinPoint连接点类作为参数传递
放行方法:proceedingJoinPoint.proceed() //放行之后回显调用放行后面的代码 然后在执行业务逻辑
10.3、注解内的表达式
10.3.1、方法级别:
@Before(execution(* com.morant.service.*.*(..)))
表示返回值类型随意 在com.morant.service包中的所有类的所有方法,参数随意
10.3.2、包级别:
@Before(within(com.morant.service))
表示在com.morant.service包中的所有类的所有方法
10.3.2、注解级别:
在com.morant.annotations里新建MyAdvice注解,并把注解放在serviceImpl类的方法上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAdvice {
}
故表达式可以写成
@Before(@annotation(com.morant.annotations.MyAdvice))
11、文件上传
11.1、Springboot上传文件要点
1、前端
表单中一定要用post提交请求,类型要设置为enctype=“multipart/form-data”
2、后端
推荐用一个绝对路径上传文件,因为jar包无法访问内部路径,我们需要注入一个绝对路径
@Controller
public class UploadController {private static final Logger log = LoggerFactory.getLogger(UploadController.class);@Value("${file.upload.dir}")private String realPath;@RequestMapping("/upload")public String upload(MultipartFile file) throws IOException {log.debug("文件类型{}",file.getContentType());log.debug("文件原文件名{}",file.getOriginalFilename());//定义新的名字String originalFilename = file.getOriginalFilename();String newName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())+originalFilename.substring(originalFilename.lastIndexOf("."));log.debug("新文件名{}",newName);//上传文件file.transferTo(new File(realPath,newName));return "redirect:/upload.jsp";}
}
3、配置:最大下载大小
注意:
substring(int i):从字符串第i为开始一直取到最后一位
上传文件的语句 :
//上传文件
file.transferTo(new File(realPath,newName));给文件取新的名字
//定义新的名字
String originalFilename = file.getOriginalFilename();
String newName = new SimpleDateFormat(“yyyyMMddHHmmssSSS”).format(new Date())+
originalFilename.substring(originalFilename.lastIndexOf("."));
log.debug(“新文件名{}”,newName);
12、文件下载
12.1、文件下载的步骤
- 确定项目中那些资源可以被下载
- 将可以被下载的资源放位置、文件上传服务器 fastdfs(dfs 分布式文件存储系统 多个节点 冗余备份)、上传OSS对象存储、七牛云。
- 项目汇总开发一个下载页面
12.2、文件下载的步骤
1、创建项目
2、引入jsp依赖
<!-- 解析-jsp--><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency>
3、jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %><!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>文件下载</title>
</head>
<body>
<h1>文件下载</h1>
<a href="${pageContext.request.contextPath}/download?fileName=a.txt">a.txt</a>
<a href="${pageContext.request.contextPath}/download?fileName=HELP.md">HELP.md</a>
<a href="${pageContext.request.contextPath}/download?fileName=中文.txt">中文.txt</a>
</body>
</html>
4、配置文件设置下载地址
server:port: 8989servlet:context-path: /springboot-downloadspring:mvc:view:prefix: /suffix: .jspfile:download:dir: D:\JavaAll\SpringBoot\springboot-download\download
5、Controller
@Controller
public class downloadController {private static final Logger log = LoggerFactory.getLogger(downloadController.class);@Value("${file.download.dir}")private String realPath;@RequestMapping("/download")public void download(String fileName, HttpServletResponse response) throws IOException {log.debug("当前下载的文件名为{}",fileName);log.debug("当前下载的文件目录为");//1.去指定目录中读取文件File file = new File(realPath,fileName);//2.将文件读取为输入流FileInputStream is = new FileInputStream(file);//3.获取响应输入流之前一定要设置附件下载格式 attachment附件response.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));//4.输入流复制给输出流ServletOutputStream os = response.getOutputStream();byte [] b= new byte[1024];int len =0;while((len=(is.read(b)))!=-1){os.write(b,0,len);}//第二种复制方法//FileCopyUtils.copy(is,os);//5.释放资源is.close();}
}
注意:
1、先要把文件转换为文件输入流
2、要设置响应消息的响应头:附件下载格式以及编码格式
3、记得要关闭流
4、不许要返回值
5、下载源文件路径在yml中配置
6、Spring框架提供文件复制类FileCopyUtils 可以进行复制
13、拦截器
13.1、过滤器的介绍
filter 过滤器:过滤器可以拦截javaweb中请求,放行,中断
强大:拦截一切资源:.jsp、html、css、img …
13.2、拦截器的作用
作用:将controller中共有代码放到拦截器中执行,减少controller中代码冗余
13.3、拦截器的特性
- 拦截器芝兰姐controller相关请求
- 拦截器可以中断请求轨迹
- 请求之前如果该请求配置了拦截器,请求会先经过拦截器,拦截器放行之后执行controller,controller执行完成后会回到拦截器继续执行拦截器中的代码
13.4、用法介绍
1、a.类 implements HandlerInterceptor 接口 引入默认实现
- preHandler 预先处理方法:拦截器最先执行的按方法,范围值为布尔类型的值(true:放行,false:中断)
- postHandler 过程中处理:controller返回之后回到postHandler这个方法执行,执行完成这个方法开始响应浏览器
- aferCompletion 最后完成:当相应结构结束后会执行拦截器这个方法中的内容
2、配置拦截器
Springmvc配置方式:MVC:interceptors springmvc.xml
springboot提供了springmvc配置接口:WebMvcConfigurer
类 implements WebMvcConfigurer{
//覆盖配置拦截器的方法
1、使用哪个拦截器
2、拦截器拦截的请求地址
3、排除哪些请求
}
13.5、例子
1、创建interceptors包 并创建两个拦截器
Interceptor1.java
package com.morant.interceptors;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*自定义拦截器*/
public class Interceptor1 implements HandlerInterceptor {private static final Logger log = LoggerFactory.getLogger(Interceptor1.class);@Override//最先执行//参数3:handler 当前请求的控制器对象 DemoController/loginpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.debug("===========1=============");//返回值为false是的重定向路径//response.sendRedirect(request.getContextPath()+"/error404.jsp");return true;}@Override//参数3:handlaer:当前控制器对象//参数4:modelAndView 模型和视图 当前请求访问的modelAndView对象public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.debug("===========2=============");}@Override//参数3:handlaer:当前控制器对象//参数4:Exception:如果控制器出现异常的对象public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.debug("===========3=============");}
}
Interceptor2.java
package com.morant.interceptors;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class Interceptor2 implements HandlerInterceptor {private static final Logger log = LoggerFactory.getLogger(Interceptor1.class);@Override//最先执行//参数3:handler 当前请求的控制器对象 DemoController/loginpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.debug("===========4=============");//返回值为false是的重定向路径//response.sendRedirect(request.getContextPath()+"/error404.jsp");return true;}@Override//参数3:handlaer:当前控制器对象//参数4:modelAndView 模型和视图 当前请求访问的modelAndView对象public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.debug("===========5=============");}@Override//参数3:handlaer:当前控制器对象//参数4:Exception:如果控制器出现异常的对象public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.debug("===========6=============");}
}
2、创建config包,并配置拦截器
package com.morant.config;import com.morant.interceptors.Interceptor1;
import com.morant.interceptors.Interceptor2;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MvcConfig implements WebMvcConfigurer {//配置拦截器的相关方法@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new Interceptor1()).addPathPatterns("/**")//所有路径.excludePathPatterns("/file/**")//除了file下的请求.order(1);//指定优先级 有限顺序为自然数顺序registry.addInterceptor(new Interceptor2()).addPathPatterns("/**")//所有路径.excludePathPatterns("/file/**")//除了file下的请求.order(2);}
}
注意:
1.配置了两个拦截器,拦截器方法的执行顺序是栈的方式,先进入拦截器的后返回controller和最后过程
14、springboot部署方式
14.1、war部署
1、设置打包方式为war
<packaging>war</packaging>
2、去除springboot项目内嵌tomcat依赖
<dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency>
3、在插件中指定入口类
3.1.configuration标签的内容是新加入的
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><!--配置springboot入口类--><fork>true</fork><!--增加jvm参数--><jvmArguments>-Dfile.encoding=UTF-8</jvmArguments><!--指定入口类--><mainClass>com.morant.SpringBootInterceptorApplication</mainClass></configuration></plugin></plugins>
</build>
3.2 修改入口类的内容(继承类、重写方法)
@SpringBootApplication
//SpringBootServletInitialize:不在使用内嵌的容器使用 使用外部的web容器启动 外部tomcat启动
public class SpringBootInterceptorApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(SpringBootInterceptorApplication.class, args);}//单单继承SpringServletIntialize不行,还要重写配置方法(配置入口是谁)@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(SpringBootInterceptorApplication.class);}
}
4、打包测试
注意:一旦使用war包部署,application.yml中配置的port端口和context-path失效。访问时使用war报名字和外部tomcat端口号进行访问
14.2、jar包部署(一般前后端分离项目)
1、默认是jar包打包 也可已进行设置
<packaging>jar</packaging>
2、打包,在target目录中获取对应的jar文件
3、启动jar包 java -jar 对应的文件名字 nohup &
15、Restful API
15.1、使用restful操作资源
- [GET] :/users #查询某用户列表
- [GET]:/users/1001 #查询某个用户信息
- [POST]:/users #新建用户信息
- [PUT]:users/1001 #更新用户信息(全部字段)
- [PATCH]:/users/1001 #更新用户信息(部分字段)
- [DELETE]:/users/1001 #删除用户信息
15.2、Restful风格测试
1、v1/controller
//@RestController:专用于restful风格 @Controller:专用于传统开发注解
@Controller
@RequestMapping("/v1/users")
public class UserController {private static final Logger log = LoggerFactory.getLogger(UserController.class);//查询某个用户的方法@GetMapping("/{id}")@ResponseBody //将控制器方法的返回值转为jsonpublic User user(@PathVariable("id") Integer id){log.debug("id=:{}",id);return new User(id,"morant",new Date(),10000.00);}//查询所有用户的方法@GetMapping@ResponseBodypublic ArrayList<User> users(){ArrayList<User> users = new ArrayList<>();users.add(new User(1,"MORANT",new Date(),1000.00));users.add(new User(2,"MORE",new Date(),1000.00));return users;}//添加一个用户//@RequestBody将前端传来的json数据转化为对象 相当于反序列@PostMapping@ResponseBody//将后端的对象转化为json传到前端显示 相当于序列话的过程public void saveuser(@RequestBody User user){log.debug("name:{} bir:{} salary{}",user.getName(),user.getBir(),user.getSalary());}//修改一个用户的全部字段@PutMapping("/{id}")@ResponseBodypublic void updateuser(@PathVariable("id") Integer id,@RequestBody User user){log.debug("id{}",user.getId());log.debug("name:{} bir:{} salary{}",user.getName(),user.getBir(),user.getSalary());}//删除一个用户@DeleteMapping("/{id}")@ResponseBodypublic void deleteuser(@PathVariable("id")Integer id){log.debug("id:{}",id);}
}
2、使用postman测试 需要开启主类
//总结
//@RestController:专用于restful风格 @Controller:专用于传统开发注解
//@RestController= @Controller + @RequestBody
//@ResponseBody 将后端的对象转化为json传到前端显示 相当于序列话的过程
//@RequestBody将前端传来的json数据转化为对象 相当于反序列
15.3、restful标准返回类型和状态码
ResponseEntity:springmvc 封装了一个专用于restful响应类,这个类在响应时可以提供响应的状态码,同时还可以自定义响应头
HttpStatus: springmvc 封装了一个枚举类型类 这个类中的是网络中的状态码
修改Controller
//查询某个用户的方法@GetMapping("/{id}")@ResponseBody //将控制器方法的返回值转为jsonpublic ResponseEntity<User> user(@PathVariable("id") Integer id){log.debug("id=:{}",id);return new ResponseEntity<>(new User(id,"morant",new Date(),10000.00), HttpStatus.OK);}
16、异常处理
16.1、传统web项目的异常处理
1、引入thymeleaf模板
<!-- 引入thymeleaf模板--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
2、配置thymeleaf
server:port: 8081spring:thymeleaf:prefix: classpath:/templates/suffix: .htmlcache: false
3、编写controller/DemoConteoller(计算和登录两个报错方法)
@Controller
@RequestMapping("/demos")
public class DemoController {@RequestMapping("/demo")public String demo(){System.out.println("demo ok....");int i =1/0;return "hello";}@RequestMapping("/login")public String login(String username,String password){if("morant".equals(username)&&"123456".equals(password)){return "hello";}else{throw new UserNameNotFondException("用户名找不到");}}
}
4、自定义用户名找不到的方法(/exception/UserNameNotFondException)
package com.morant.exception;public class UserNameNotFondException extends RuntimeException{public UserNameNotFondException(String message) {super(message);}
}
5、创建exception/GlobalExceptionResolver继承HandlerExceptResolver
@Component//将该类加载进入工厂
public class GlobalExceptionResolver implements HandlerExceptionResolver {//resolveException:当前控制器中的任何一个方法发生异常时,如果该控制器的方法没有自己处理异常(try...catch),则会进入该方法//注意 在异常处理的方法中,完成自己的异常处理//参数1:当前请求对象//参数2:当前请求对应的响应头//参数3:当前出现错误的方法//参数4:出现异常的异常对象//返回值:模型和视图@Overridepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {System.out.println("这是全局异常处理");System.out.println("当前异常为"+ex);ModelAndView modelAndView = new ModelAndView();if(ex instanceof UserNameNotFondException){modelAndView.setViewName("login");return modelAndView;}modelAndView.setViewName("500");return modelAndView;}
}
总结
自定义的全局异常处理对象GlobalExceptionResolver需要使用@Component注解在spring工厂中进行注册
HandlerExceptionResolver:spring为我们提供的一个接口 作用于所有控制器报错的情况 我们只需要自己定义一个全局异常处理对象去继承该接口
16.2、前后端分离项目的异常处理
前后端的交互采用ajax的方式
1、创建 controller/DemoController类
@RestController
@RequestMapping("/demo")
public class DemoController {@GetMappingpublic ResponseEntity<String> demo(){System.out.println("demo ok");int n=1/0;return new ResponseEntity<String>("demo ok", HttpStatus.OK);}@GetMapping("{id}")public ResponseEntity<Integer> demo1(@PathVariable Integer id){System.out.println("demo ok");if (id==0) {throw new IllegalNumberException("输入非法数字");}return new ResponseEntity<Integer>(1/id, HttpStatus.OK);}
}
2、定义自定义异常(非法数字异常)
public class IllegalNumberException extends RuntimeException{public IllegalNumberException(String message) {super(message);}
}
3、创建exception/GlobalExceptionResolver类(添加@ControllerAdvice注解)
@ControllerAdvice
public class GlobalExceptionResolver {@ExceptionHandler(value = RuntimeException.class) //用在方法上public ResponseEntity<String> exceptionHandler1(Exception ex){//这个方法名随便起System.out.println("进入数字异常");return new ResponseEntity<String>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);}@ExceptionHandler(value = Exception.class) //用在方法上public ResponseEntity<String> exceptionHandler(Exception ex){//这个方法名随便起System.out.println("进入自定义异常处理");return new ResponseEntity<String>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);}
}
总结:
@ControllerAdvice:注解可以使得controller的错误在这这个类中进行处理
@ExceptionHandler(value = Exception.class) :对应controller抛出的错误类型(就近原则,没有一一对应的就找value = Exception.class)
17、CORS
1.什么是CORS
**定义:**跨域资源共享
2.什么是跨域资源共享
解释:语序浏览器可以从当前服务器通过ajax访问另一个源服务地址
3.同源策略
是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。同源是浏览器安全的基石。
4.什么是源(orign)
源【orign】就是协议、域名、端口号。例如:http://www.baiodu.com:80这个url
协议:http
域名:www.baidu.com
端口号:80
5.哪些操作不会受到同源的限制
<script src=""/script>
<img>
<link>
<iframe>
6.那些操作会受到同源限制
ajax
出现跨域:Acsee-Control-Allow-Orign
7.springboot中如何解决跨域问题
- 局部:在每一个Controller中假如@CrossOrign注解
- 全局:
package com.morant.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;@Configuration
public class CorsConfig{@Beanpublic CorsFilter corsFilter(){UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*");//语序任何域名使用corsConfiguration.addAllowedHeader("*");//允许任何头corsConfiguration.addAllowedMethod("*");//语序任何方法(post,get等)source.registerCorsConfiguration("/**",corsConfiguration);//处理所有请求的跨域配置return new CorsFilter(source);}
}
/这个方法名随便起
System.out.println(“进入数字异常”);
return new ResponseEntity(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(value = Exception.class) //用在方法上
public ResponseEntity<String> exceptionHandler(Exception ex){//这个方法名随便起System.out.println("进入自定义异常处理");return new ResponseEntity<String>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
> 总结:
>
> @ControllerAdvice:注解可以使得controller的错误在这这个类中进行处理
>
> @ExceptionHandler(value = Exception.class) :对应controller抛出的错误类型(就近原则,没有一一对应的就找value = Exception.class)## 17、CORS1.什么是CORS **定义:**跨域资源共享2.什么是跨域资源共享 **解释**:语序浏览器可以从当前服务器通过ajax访问另一个源服务地址3.同源策略 是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。同源是浏览器安全的基石。4.什么是源(orign) 源【orign】就是协议、域名、端口号。例如:http://www.baiodu.com:80这个url 协议:http 域名:www.baidu.com 端口号:805.哪些操作不会受到同源的限制```html
<script src=""/script>
<img>
<link>
<iframe>
6.那些操作会受到同源限制
ajax
出现跨域:Acsee-Control-Allow-Orign
7.springboot中如何解决跨域问题
- 局部:在每一个Controller中假如@CrossOrign注解
- 全局:
package com.morant.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;@Configuration
public class CorsConfig{@Beanpublic CorsFilter corsFilter(){UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*");//语序任何域名使用corsConfiguration.addAllowedHeader("*");//允许任何头corsConfiguration.addAllowedMethod("*");//语序任何方法(post,get等)source.registerCorsConfiguration("/**",corsConfiguration);//处理所有请求的跨域配置return new CorsFilter(source);}
}
Springboot(编程不良人)相关推荐
- 【编程不良人】快速入门SpringBoot学习笔记06---RestFul、异常处理、CORS跨域、Jasypt加密
1. RestFul 配套视频:[编程不良人]2021年SpringBoot最新最全教程_哔哩哔哩_bilibili 1.1 引言 REST全称是(Resources) Representationa ...
- 【编程不良人】快速入门Spring学习笔记08---事务属性、Spring整合Structs2框架(SM)、Spring整合Mybatis+Struts2(SSM)、Spring注解、SSM注解式开发
1. 事务属性 1.1 事务传播属性 配套视频:[编程不良人]快速入门Spring,SpringBoot.SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili # ...
- jwt实战详解--B站编程不良人视频笔记
文章目录 前言 一.什么是JWT 二.JWT能做什么 1.授权 2.信息交换 三.为什么使用JWT 四.JWT的结构是什么 五.使用JWT 1.引入依赖 2.生成token 3.根据令牌和签名解析数据 ...
- 【编程不良人】MongoDB最新实战教程学习笔记
简介 视频链接:01.简介和历史_哔哩哔哩_bilibili 文档地址: https://docs.mongodb.com/manual/ MongoDB教程:MongoDB 教程 | 菜鸟教程 注意 ...
- Hadoop 从入门到精通----leo学习编程不良人视频的笔记--part01
编程不良人原版笔记 - https://blog.csdn.net/wei198621/article/details/111280555 part 01 hadoop 集群的搭建 – https:/ ...
- Hadoop 从入门到精通----编程不良人笔记
编程不良人原版笔记 - https://blog.csdn.net/wei198621/article/details/111280555 part 01 hadoop 集群的搭建 – https:/ ...
- 【编程不良人】SpringSecurity实战学习笔记07---授权
配套视频:61.授权之授权核心概念_哔哩哔哩_bilibili 什么是权限管理? 权限管理核心概念 Spring Security权限管理策略 基于URL地址方式实现的权限管理 基于方法实现的权限管理 ...
- B站【编程不良人】Redis教程整理学习笔记(超详细拓展)
Redis 1. NoSQL的引言 NoSQL( Not Only SQL ),意即不仅仅是SQL, 泛指非关系型的数据库.Nosql这个技术门类,早期就有人提出,发展至2009年趋势越发高涨. 2. ...
- Docker学习视频笔记【编程不良人】
1.Docker介绍 2.Docker与虚拟机对比 3.Docker引擎安装 4.Docker中核心概念 5.Docker核心架构图 6.配置阿里云镜像加速 Docker 配置国内镜像源_hub-mi ...
最新文章
- 学习旧岛小程序 (3)组件的样式
- udp java 编程_JAVA 网络编程之UDP编程
- sql中索引不会被用到的几种情况
- vue进入页面执行的钩子函数_解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题...
- java中finalizer终结方法学习心得
- Linux(debian7)操作基础(十五)之systemd下lightdm免密登录
- mangTomany 自关联之个人感悟
- 【转】Qt QTableview使用
- spring boot @value_spring+vue全栈开发实战-第二章Spring Boot 基础配置-笔记0302-2020
- centos7 里面dump_centos7使用lldb调试netcore应用转储dump文件
- qt最大化和还原实现_Qt 窗口操作函数(置顶、全屏,最大化最小化按钮设置等)...
- 编程实现二叉树的遍历
- 算法图解第八章笔记与习题(贪婪算法)
- c语言数列求和程序137,C语言循环结构
-C语言数列求和(使用while循环)
- 在eclipse中编写word count的Java程序打包到虚拟机中运行
- 多步攻击场景构建和攻击链提取方法
- Selenium的文件上传和操作Cookie等方法_Sinno_Song_新浪博客
- SQLServer2008R2安装和使用
- android gettext方法,android – getString()和getText()有什么区别?
- 从OJB到Hibernate的迁移
热门文章
- 物联网基础:EC20 连接阿里云进行数据收发
- 2022 主站及创作侧年度总结 - 相信未来、期待未来
- 作为一名工程师,你应该专注于成为一名多面手还是专家?
- mysql dml语句 先读取在更新_事务的4个特性——ACID(原子性、一致性、隔离性和持久性)、更新丢失问题...
- 智能手表短信读取实现具体教程(带有eSIM卡,无短信功能,可安装手表QQ的智能手表)Version2.0改进版
- 计算机德育教育课题,德育教育研究课题有哪些研究方向
- 51单片机五层电梯控制器 基于51单片机的五层电梯控制系统
- Qt优秀开源项目之十二:shotcut
- GAN生成对抗网络合集(七):cycleGAN—循环损失的提出 / starGAN
- 火狐浏览器打开b站默认静音解决办法