SpringMVC 传参定义类型转换

SpringMVC 中的转换器 表单提交的任何数据类型全部都是字符串类型,但是后台定义接收类型是 Integer 类型,数据也可以封装上,说明 Spring 框架内部会默认进行数据类型转换。 自定义类型转换器 已知有自带的类型转换器,但在特殊情况下可能并不能满足需要,那如何自定义使用类型转换器呢? 例如,前台输入 2019/08/08 在后端可以被 Date 接收,但是前台传的是 2019-08-08 怎么办,直接写会报错,转换器代码如下:import org.springframework.core.convert.converter.Converter;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;/** * 自定义日期转换 Converter 中泛型第一个指转换的原类型,第二个是目标转换类型 */public class StringToDateConverter implements Converter<String, Date> { /** * 进行类型转换的方法 */ @Override public Date convert(String source) {// 判断 source 其实就是值 SpringMVC 传来的值 if(source == null) {// 运行时异常 运行出错停止运行 throw new RuntimeException(" 参数不能为空 "); }try {DateFormat df = new SimpleDateFormat("yyyy-MM-dd");// 解析字符串 Date date = df.parse(source); return date; } catch (Exception e) {throw new RuntimeException(" 类型转换错误 "); } }} 开始在 springmvc.xml 中配置自定义的转换器 <!-- 注册自定义类型转换器 --><bean id="conversionService"class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.cway.utils.StringToDateConverter"/> </set> </property></bean><!-- 开启 Spring 对 MVC 注解的支持 增加类型转换器 --><mvc:annotation-driven conversion-service="conversionService"/>

JBarcode 生成一维条形码工具

转自网络,工具类:import java.awt.Color;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.image.BufferedImage;import java.io.*;import java.util.ArrayList;import java.util.List;import org.jbarcode.JBarcode;import org.jbarcode.JBarcodeFactory;import org.jbarcode.encode.Code128Encoder;import org.jbarcode.encode.InvalidAtributeException;import org.jbarcode.paint.TextPainter;import org.jbarcode.util.ImageUtil;/** * Author: Cheng * Date: 2019/7/29 * Time: 15:11 * Description: No Description */public class JbarcodeUtil {    // 设置条形码高度    private static final int BARCODE_HEIGHT = 40;    // 设置条形码默认分辨率    private static final int BARCODE_DPI = ImageUtil.DEFAULT_DPI;    // 设置条形码字体样式    private static final String FONT_FAMILY = "console";    // 设置条形码字体大小    private static final int FONT_SIZE = 15;    // 设置条形码文本    public static String TEXT = "";    // 创建 jbarcode    private static JBarcode jbc = null;    static JBarcode getJBarcode() throws InvalidAtributeException {        /**         *  参考设置样式:         *barcode.setEncoder(Code128Encoder.getInstance()); // 设置编码         *barcode.setPainter(WidthCodedPainter.getInstance());//  设置 Painter         *barcode.setTextPainter(BaseLineTextPainter.getInstance()); // 设置 TextPainter         *barcode.setBarHeight(17); // 设置高度         *barcode.setWideRatio(Double.valueOf(30).doubleValue());//  设置宽度比率         *barcode.setXDimension(Double.valueOf(2).doubleValue()); //  设置尺寸,大小   密集程度         *barcode.setShowText(true); // 是否显示文本         *barcode.setCheckDigit(true); // 是否检查数字         *barcode.setShowCheckDigit(false); // 是否显示检查数字         */        if (jbc == null) {            // 生成 code128            jbc = JBarcodeFactory.getInstance().createCode128();            jbc.setEncoder(Code128Encoder.getInstance());            jbc.setTextPainter(CustomTextPainter.getInstance());            jbc.setBarHeight(22);            jbc.setXDimension(Double.valueOf(0.8).doubleValue());            jbc.setShowText(false);        }        return jbc;    }    /**     * @descript: 生成条形码文件     * @param message   条形码内容     * @param file    生成文件     */    public static void createBarcode(String message, File file,String text) {        try {            FileOutputStream fos = new FileOutputStream(file);            createBarcode(message, fos,text);            fos.close();        } catch (IOException e) {            throw new RuntimeException(e);        }    }    /**     * @descript: 生成条形码并写入指定输出流     * @param message    条形码内容     * @param os    输出流     */    public static BufferedImage createBarcode(String message, OutputStream os,String text) {        try {            // 设置条形码文本            TEXT=text;            // 创建条形码的 BufferedImage 图像            BufferedImage image = getJBarcode().createBarcode(message);            ImageUtil.encodeAndWrite(image, ImageUtil.PNG, os, BARCODE_DPI, BARCODE_DPI);            os.flush();            return image;        } catch (Exception e) {            throw new RuntimeException(e);        }    }    /**     *  静态内部类     *  自定义的  TextPainter,  允许定义字体,大小,文本等     *  参考底层实现:BaseLineTextPainter.getInstance()     */    protected static class CustomTextPainter implements TextPainter {        private static CustomTextPainter instance =new CustomTextPainter();        public static CustomTextPainter getInstance() {            return instance;        }        @Override        public void paintText(BufferedImage barCodeImage, String text, int width) {            // 绘图            Graphics g2d = barCodeImage.getGraphics();            // 创建字体            Font font = new Font(FONT_FAMILY, Font.PLAIN, FONT_SIZE * width);            g2d.setFont(font);            FontMetrics fm = g2d.getFontMetrics();            int height = fm.getHeight();            int center = (barCodeImage.getWidth() - fm.stringWidth(text)) / 2;            g2d.setColor(Color.WHITE);            g2d.fillRect(0, 0, barCodeImage.getWidth(), barCodeImage.getHeight() * 1 / 20);            g2d.fillRect(0, barCodeImage.getHeight() - (height * 9 / 10), barCodeImage.getWidth(), (height * 9 / 10));            g2d.setColor(Color.BLACK);            // 绘制文本            g2d.drawString(TEXT, 0, 145);            // 绘制条形码            g2d.drawString(text, center, barCodeImage.getHeight() - (height / 10) - 2);        }    }    // 测试    public static void main(String[] args) throws FileNotFoundException, IOException {        List<String> list=new ArrayList<String>();        list.add("KJ4.1-0127-0001");        list.add("KJ4.1-0128-0001");        list.add("KJ4.1-0129-0001");        list.add("KJ4.1-0130-0001");        if(list!=null && list.size()>0){            for(String message:list){                JbarcodeUtil.createBarcode(message, new File("D:\\pdf\\"+message+".png")," 苏交科 ");//                ByteArrayOutputStream os = new ByteArrayOutputStream();//                JbarcodeUtil.createBarcode(message,os," 苏交科 ");//                System.out.println(os);            }        }    }} 这里我调用了上面的 BufferedImage createBarcode(...) 方法,返回图片类型使用在下列即可。 在 itext 方法的单元格中加入二维码图片,其中 cl2 是其中一个单元格。            ByteArrayOutputStream barOut = new ByteArrayOutputStream();            ImageIO.write(codeImage, "png", barOut);            cl2.addElement(Image.getInstance(barOut.toByteArray())); //cl2 为单元格

Oracle 数据库入门教程与常用语法介绍

Oracle 安装好后配置 文件夹 C:\oracle\product\10.2.0\db_1\NETWORK\ADMIN 中修改 listener.ora 文件,将 HOST= 后边字符改成本机 ip 地址或者本机的计算机名。# listener.ora Network Configuration File: C:\oracle\product\10.2.0\db_1\network\admin\listener.ora# Generated by Oracle configuration tools.SID_LIST_LISTENER =  (SID_LIST =    (SID_DESC =      (SID_NAME = PLSExtProc)      (ORACLE_HOME = C:\oracle\product\10.2.0\db_1)      (PROGRAM = extproc)    )  )LISTENER =  (DESCRIPTION_LIST =    (DESCRIPTION =      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))      (ADDRESS = (PROTOCOL = TCP)(HOST = PC-7DE0D8D1)(PORT = 1521))    )  )同理修改 tnsnames.ora# tnsnames.ora Network Configuration File: C:\oracle\product\10.2.0\db_1\network\admin\tnsnames.ora# Generated by Oracle configuration tools.ORCL =  (DESCRIPTION =    (ADDRESS = (PROTOCOL = TCP)(HOST = PC-7DE0D8D1)(PORT = 1521))    (CONNECT_DATA =      (SERVER = DEDICATED)      (SERVICE_NAME = orcl)    )  )EXTPROC_CONNECTION_DATA =  (DESCRIPTION =    (ADDRESS_LIST =      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))    )    (CONNECT_DATA =      (SID = PLSExtProc)      (PRESENTATION = RO)    )  )在计算机管理中启动下列两个服务 PL/SQL 登录 oracle 第一次登陆点取消,进去点 Tools->Preference,设置 instantclient 的路径与 oci登录 Datebase 例如:192.168.43.218:1521/orcl若想自动登陆,可将 tnsnames.ora 放在本地任意文件夹,例如我还是放在路径中,配置环境变量TNS_ADMIND:\java\instantclient_12_1Oracle 简介 数据库 oracle 数据库是物理储存,和 mysql 不同的是 mysql 中管理表的是数据库,而 oracle 是用户。 实例 一个 Oracle 实例(Oracle Instance)有一系列的后台进程(Backguound Processes)和内存结构(Memory Structures)组成。一个数据库可以有 n 个实例。用户 用户是在实例下建立的。不同实例可以建相同名字的用户。表空间 表空间是 Oracle 对物理数据库上相关数据文件(ORA 或者 DBF 文件)的逻辑映射。一个数据库在逻辑上被划分成一到若干个表空间,每个表空间包含了在逻辑上相关联的一组结构。每 个数据库至少有一个表空间 (称之为 system 表空间)。每个表空间由同一磁盘上的一个或多个文件组成,这些文件叫数据文件(datafile)。一个数据文件只能属于一个表空间。 数据文件(dbf、ora)数据文件是数据库的物理存储单位。数据库的数据是存储在表空间中的,真正是在某一个或者多个数据文件中。而一个表空间可以由一个或多个数据文件组成,一个数据文件只能属于一个表空间。一旦数据文件被加入到某个表空间后,就不能删除这个文件,如果要删除某个数据文件,只能删除其所属于的表空间才行。不同用户可以在同一个表空间建立同名表,因为它是根据用户管理的。具体 SQL 操作 创建表空间create tablespace users -- 创建表空间datafile 'c:\users.dbf' -- 定义物理路径size 100m -- 定义大小autoextend on -- 大小超过 100m 自动扩容next 10m; -- 每次扩容大小 创建的数据文件不能被删除,删除可先删除表空间再删除文件 drop tablespace users 创建用户-- 创建用户create user zhangsan -- 账号identified by mima -- 密码default tablespace users; -- 所属表空间 用户授权connect-- 连接角色,基本角色resource-- 开发者角色dba-- 超级管理员角色 grant dba to zhangsan; -- 给张三授予 dba 角色在管理员账号执行 数据类型Varchar, varchar2 表示一个字符串NUMBER NUMBER(n)表示一个整数,长度是 nNUMBER(m,n): 表示一个小数,总长度是 m,小数是 n,整数是 m-nDATA 表示日期类型CLOB 大对象,表示大文本数据类型,可存 4GBLOB 大对象,表示二进制数据,可存 4G创建修改表及增删改查--- 创建一个 person 表create table person(       pid number(20),       pname varchar2(10));--- 修改表结构--- 添加一列alter table person add (gender number(1));--- 修改列类型alter table person modify gender char(1);--- 修改列名称alter table person rename column gender to sex;--- 删除一列alter table person drop column sex;--- 查询表中记录select * from person;---- 添加一条记录insert into person (pid, pname) values (1, ' 小明 ');commit;---- 修改一条记录update person set pname = ' 小马 ' where pid = 1;commit;---- 三个删除-- 删除表中全部记录delete from person;-- 删除表结构drop table person;-- 先删除表,再次创建表。效果等同于删除表中全部记录。-- 在数据量大的情况下,尤其在表中带有索引的情况下,该操作效率高。-- 索引可以提供查询效率,但是会影响增删改效率。truncate table person;增删改记得提交 commit,rollback 回滚 用序列完成 ID 自增Oracle 不像 mysql 等数据库有自增列,实现主键 id 自增可以用数列实现。---- 序列不真的属于任何一张表,但是可以逻辑和表做绑定。---- 序列:默认从 1 开始,依次递增,主要用来给主键赋值使用。----dual:虚表,只是为了补全语法,没有任何意义。create sequence s_person;select s_person.nextval from dual;---- 添加一条记录insert into person (pid, pname) values (s_person.nextval, ' 小明 ');commit;select * from person;select seqpersonid.nextval from dual;select seqpersonid.currval from dual;第一次执行,先执行 next 才能使用 currval 查到当前数据 初学者 Scott 用户scott 用户内包含一些简单的示例表,方便学习,使用前先用管理员账号解锁该用户。----scott 用户,密码 tiger。-- 解锁 scott 用户alter user scott account unlock;-- 解锁 scott 用户的密码【此句也可以用来重置密码】alter user scott identified by tiger;-- 切换到 scott 用户下 单行函数-- 单行函数:作用于一行,返回一个值。--- 字符函数select upper('yes') from dual;--YESselect lower('YES') from dual;--yes---- 数值函数select round(56.16, -2) from dual;--- 四舍五入,后面的参数表示保留的位数,正数往后面余,负数往前面,例如上句舍后为 100select trunc(56.16, -1) from dual;--- 直接截取,不在看后面位数的数字是否大于 5.select mod(10, 3) from dual;--- 求余数---- 日期函数---- 查询出 emp 表中所有员工入职距离现在几天。select sysdate-e.hiredate from emp e;---- 算出明天此刻select sysdate+1 from dual;---- 查询出 emp 表中所有员工入职距离现在几月。select months_between(sysdate,e.hiredate) from emp e;---- 查询出 emp 表中所有员工入职距离现在几年。select months_between(sysdate,e.hiredate)/12 from emp e;---- 查询出 emp 表中所有员工入职距离现在几周。select round((sysdate-e.hiredate)/7) from emp e;---- 转换函数--- 日期转字符串  fm 去除时间显示中填充 0   例如下列  2019-7-28 1:1:1select to_char(sysdate, 'fm yyyy-mm-dd hh24:mi:ss') from dual;--- 字符串转日期select to_date('2018-6-7 16:39:50', 'fm yyyy-mm-dd hh24:mi:ss') from dual;---- 通用函数  nvl 可排除 null 值   给 null 指定默认值--- 算出 emp 表中所有员工的年薪  ---- 奖金里面有 null 值,如果 null 值和任意数字做算术运算,结果都是 null。select e.sal*12+nvl(e.comm, 0) from emp e;条件表达式 虽然 oracle 专用写法更简单,但建议写通用的。--- 条件表达式的通用写法,mysql 和 oracle 通用--- 给 emp 表中员工起中文名   下列 else 可以省略select e.ename,        case e.ename         when 'SMITH' then ' 曹贼 '           when 'ALLEN' then ' 大耳贼 '             when 'WARD' then ' 诸葛小儿 '               --else ' 无名 '                 endfrom emp e;--- 判断 emp 表中员工工资,如果高于 3000 显示高收入,如果高于 1500 低于 3000 显示中等收入,----- 其余显示低收入select e.sal,        case          when e.sal>3000 then ' 高收入 '           when e.sal>1500 then ' 中等收入 '               else ' 低收入 '                 endfrom emp e;----oracle 中除了起别名,都用单引号。别名只能加双引号或不加引号。----oracle 专用条件表达式select e.ename,         decode(e.ename,          'SMITH',  ' 曹贼 ',            'ALLEN',  ' 大耳贼 ',              'WARD',  ' 诸葛小儿 ',                ' 无名 ') " 中文名 "             from emp e;多行 / 分组函数 注意:与 MySQL 不同的是,Oracle 中 group by 后面出现的列才能在 select 上写,而不是可以 select * 显示所有列字段-- 多行函数【聚合函数】:作用于多行,返回一个值。--count(*)底层就是 count(1)select count(1) from emp;--- 查询总数量select sum(sal) from emp;--- 工资总和select max(sal) from emp;--- 最大工资select min(sal) from emp;--- 最低工资select avg(sal) from emp;--- 平均工资--- 分组查询--- 查询出每个部门的平均工资--- 分组查询中,出现在 group by 后面的原始列,才能出现在 select 后面--- 没有出现在 group by 后面的列,想在 select 后面,必须加上聚合函数。--- 聚合函数有一个特性,可以把多行记录变成一个值。select e.deptno, avg(e.sal)--, e.enamefrom emp egroup by e.deptno;--- 查询出平均工资高于 2000 的部门信息select e.deptno, avg(e.sal) asalfrom emp egroup by e.deptnohaving avg(e.sal)>2000;--- 所有条件都不能使用别名来判断。-- 比如下面的条件语句也不能使用别名当条件select ename, sal s from emp where sal>1500;--- 查询出每个部门工资高于 800 的员工的平均工资--- 条件无论是 where 还是 having 都不能用别名select e.deptno, avg(e.sal) asalfrom emp ewhere e.sal>800group by e.deptno;----where 是过滤分组前的数据,having 是过滤分组后的数据。--- 表现形式:where 必须在 group by 之前,having 是在 group by 之后。--- 查询出每个部门工资高于 800 的员工的平均工资--- 然后再查询出平均工资高于 2000 的部门select e.deptno, avg(e.sal) asalfrom emp ewhere e.sal>800group by e.deptnohaving avg(e.sal)>2000;多表查询--- 笛卡尔积select *from emp e, dept d;--- 等值连接(推荐)select *from emp e, dept dwhere e.deptno=d.deptno;--- 内连接   与等值连接相同select *from emp e inner join dept don e.deptno = d.deptno;--- 查询出所有部门,以及部门下的员工信息。【外连接】select *from emp e right join dept don e.deptno=d.deptno;--- 查询所有员工信息,以及员工所属部门select *from emp e left join dept don e.deptno=d.deptno;---oracle 中专用外连接   例如下列等于上方 right joinselect *from emp e, dept dwhere e.deptno(+) = d.deptno;--- 还是以前建议,能用通用就别用专用 自连接select * from emp;--- 查询出员工姓名,员工领导姓名--- 自连接:自连接其实就是站在不同的角度把一张表看成多张表。select e1.ename, e2.enamefrom emp e1, emp e2where e1.mgr = e2.empno;------ 查询出员工姓名,员工部门名称,员工领导姓名,员工领导部门名称select e1.ename, d1.dname, e2.ename, d2.dnamefrom emp e1, emp e2, dept d1, dept d2where e1.mgr = e2.empnoand e1.deptno=d1.deptnoand e2.deptno=d2.deptno;子查询--- 子查询返回一个值--- 查询出工资和 SCOTT 一样的员工信息select * from emp where sal in(select sal from emp where ename = 'SCOTT')--- 子查询返回一个集合--- 查询出工资和 10 号部门任意员工一样的员工信息select * from emp where sal in(select sal from emp where deptno = 10);--- 子查询返回一张表--- 查询出每个部门最低工资,和最低工资员工姓名,和该员工所在部门名称---1,先查询出每个部门最低工资select deptno, min(sal) msalfrom emp group by deptno;---2,三表联查,得到最终结果。select t.deptno, t.msal, e.ename, d.dnamefrom (select deptno, min(sal) msal      from emp       group by deptno) t, emp e, dept dwhere t.deptno = e.deptnoand t.msal = e.saland e.deptno = d.deptno;分页查询----oracle 中的分页---rownum 行号:当我们做 select 操作的时候,-- 每查询出一行记录,就会在该行上加上一个行号,-- 行号从 1 开始,依次递增,不能跳着走。---- 排序操作会影响 rownum 的顺序select rownum, e.* from emp e order by e.sal desc---- 如果涉及到排序,但是还要使用 rownum 的话,我们可以再次嵌套查询。select rownum, t.* from(select rownum, e.* from emp e order by e.sal desc) t;----emp 表工资倒叙排列后,每页五条记录,查询第二页。----rownum 行号不能写上大于一个正数。select * from(    select rownum rn, tt.* from(          select * from emp order by sal desc    ) tt where rownum<11) where rn>5改成 mybatis 形式解读select * from(    select rownum rn, tt.* from(                 SELECT * FROM TYD) tt where rownum<=10  --size*page) where rn>5  --SIZE*(page-1)另一种写法(不推荐,做 order by 操作不能用)select * from (select rownum r ,emp.* from emp) bwhere b.r >5 and b.r <11Mybatis 分页SELECT *FROM (SELECT tb.*, ROWNUM ROW_IDFROM (...) tbWHERE ROWNUM <![CDATA[<=]]> #{page} * #{rows})WHERE ROW_ID <![CDATA[>]]> (#{page} - 1) * #{rows}

Oracle 数据库入门教程与常用语法介绍

### Cause: java.sql.SQLException: ORA-00918: 未明确定义列

Oracle 在 mybatis 中查询出错,加了分页嵌套语句,单查里面的 SQL 没问题,于是我将 SQL 复制到 Navicat 上执行,报错:[Err] ORA-00918: column ambiguously defined 百度得知是在嵌套语句时候有字段重复,也就是一样的,它无法分辨是子表里的还是哪张表中的字段,这种情况给表字段都起个别名即可

ORA-01658: 无法为表空间 XXX 段创建 INITIAL 区

ORA-01658: unable to create INITIAL extent for segment in tablespace string 用 Navicat 操作 oracle 建表时候发生如上错误,百度搜了下也有类似解决方法,例如:https://blog.csdn.net/j080624/article/details/78731412 但是我操作的 oracle 有自己的表空间,应该不能给现有表空间扩容,于是,我了解到数据表应该存在其中某个表空间。立马操作:Navicat 打开刚刚建好的表,右键点“设计”,然后在 tab 上点“选项”,然后切换到自己需要的表空间即可,实体属性如果不知道切勿修改,乱改的话可能会保存不了。 如何避免这种错误?在建表时就对表空间进行指定,其中 NAMES 指代指定的表空间,按实际情况修改,以下参数也是根据实际情况改:tablespace NAMES  pctfree 10  initrans 1  maxtrans 255  storage  (    initial 64K    next 8K    minextents 1    maxextents unlimited  )

IDEA 用 SQL Dialect 设置 mapper.xml 的方言并格式化

我们在用 idea 写 ssm 的 mapper 文件的时候,经常会发现有一大块黄色区域标记的字符,并且使用 idea 自带的格式化功能 sql 语句也不能正确得格式化,使得 mapper 文件看起来杂乱无章。那么怎么能让 sql 能正确格式化呢?1、第一种方式,光标放在 xml 文件中一行 sql 中,按 alt+enter,弹出的对话框选择第一个选项,然后在里面选择合适的 SQL 类型,例如 oracle 或 mysql2、第二种,如果设置错了方言造成没有第一种的选项:同样打开某个 mapper.xml 文件,再打开 Setting 设置,搜索 SQL Dialect,然后将 SQL 语言改成合适的版本即可 然后你再用 idea 快捷键格式化就会发现 SQL 按照标准格式化好了 3、第三种,同第二种一样,可以双机 shift,然后在搜索框输入“sql dia”搜索相关功能打开也可以 拓展:SQL Dialect 中 Dialect 即方言的意思,上面操作意图很明了,更改 SQL 的方言。

IDEA 用 SQL Dialect 设置 mapper.xml 的方言并格式化

显示随机图片随机照片 URL 收集

https://acg.toubiec.cn/random.phphttp://img.xjh.me/random_img.php?type=bg&ctype=nature&return=302(自然)http://img.xjh.me/random_img.php?tctype=acg&return=302 (竖屏)http://img.xjh.me/random_img.php?type=bg&ctype=acg&return=302https://uploadbeta.com/api/pictures/random/http://api.mtyqx.cn/tapi/random.phphttp://api.mtyqx.cn/api/random.phphttps://random.52ecy.cn/randbg.phphttps://api.ixiaowai.cn/api/api.phphttps://api.ixiaowai.cn/mcapi/mcapi.php 一言 Api:https://api.ixiaowai.cn/api/ylapi.php

SpringMVC 拦截器

SpringMVC 拦截器 SpringMVC 框架中的拦截器用于对处理器进行预处理和后处理的技术。 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。拦截器和过滤器的功能比较类似,有区别1.  过滤器是 Servlet 规范的一部分,任何框架都可以使用过滤器技术。 2.  拦截器是 SpringMVC 框架独有的,因此只对控制器方法产生作用。 3.  过滤器配置了 /*,可以拦截任何资源,因此静态资源需要在配置中排除。springmvc.xml 配置静态资源过滤<!-- location  表示路径,mapping  表示文件,** 表示该目录下的文件以及子目录的文件  --><mvc:resources location="/css/" mapping="/css/**"/><mvc:resources location="/images/" mapping="/images/**"/><mvc:resources location="/scripts/" mapping="/javascript/**"/>拦截器只会对控制器中的方法进行拦截。拦截器也是 AOP 思想的一种实现方式 想要自定义拦截器,需要实现 HandlerInterceptor 接口,然后根据需要重写里面方法。简而言之拦截器就是对控制层执行前后进行处理的工具,之前学过的 @ModelAttribute 注解也可以对 Controller 参数进行预处理,只是 @ModelAttribute 只是将处理好参数返给控制器了。拦截器明显可以做更多事,例如看请求中是否包含某信息,不包含则跳转到错误页面,包含则正常执行控制层。自定义拦截器步骤 创建类,实现 HandlerInterceptor 接口,idea 按 ctrl+ o 重写需要方法,返回 true 放行,反之拦截。可以做登录前的验证,未登录预处理重定向或转发跳转到登录页面。public class MyInterceptor1 implements HandlerInterceptor {    /**     * controller 方法执行前,进行拦截的方法     * return true 放行     * return false 拦截     *  可以使用转发或者重定向直接跳转到指定的页面。     */    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler)            throws Exception {        System.out.println(" 拦截器执行了...");        return true;    }}配置 springmvc.xml,以下配置了两拦截器,执行顺序,12->Controller->21->JSP->21<!--  配置拦截器  --><mvc:interceptors>    <mvc:interceptor>        <!--  哪些方法进行拦截  -->        <mvc:mapping path="/user/*"/>        <!--  哪些方法不进行拦截        <mvc:exclude-mapping path=""/>        -->        <!--  注册拦截器对象  -->        <bean class="cn.cheng.demo1.MyInterceptor1"/>    </mvc:interceptor>            <mvc:interceptor>        <!--  哪些方法进行拦截  -->        <mvc:mapping path="/**"/>        <!--  哪些方法不进行拦截        <mvc:exclude-mapping path=""/>        -->        <!--  注册拦截器对象  -->        <bean class="cn.cheng.demo1.MyInterceptor2"/>    </mvc:interceptor></mvc:interceptors>preHandle 方法是 controller 方法执行前拦截的方法 可以使用 request 或者 response 跳转到指定的页面 return true 放行,执行下一个拦截器,如果没有拦截器,执行 controller 中的方法。return false 不放行,不会执行 controller 中的方法。postHandle 是 controller 方法执行后执行的方法,在 JSP 视图执行前。 可以使用 request 或者 response 跳转到指定的页面 如果指定了跳转的页面,那么 controller 方法跳转的页面将不会显示。afterHandle 方法是在 JSP 执行后执行request 或者 response 不能再跳转页面了

SpringMVC 异常处理

异常处理 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。编写异常类public class CustomException extends Exception {    private String message;    public CustomException(String message) {        this.message = message;    }    public String getMessage() {        return message;    }}自定义异常处理器 设置如果是指定错误跳转到指定错误页面,并返回相应错误信息public class CustomExceptionResolver implements HandlerExceptionResolver {    @Override    public ModelAndView resolveException(HttpServletRequest request,                                         HttpServletResponse response, Object handler, Exception ex) {        ex.printStackTrace();        CustomException customException = null;// 如果抛出的是系统自定义异常则直接转换        if (ex instanceof CustomException) {            customException = (CustomException) ex;        } else {// 如果抛出的不是系统自定义异常则重新构造一个系统错误异常。            customException = new CustomException(" 系统错误,请与系统管理   员联系!");        }        ModelAndView modelAndView = new ModelAndView();        // 存入错误信息        modelAndView.addObject("message", customException.getMessage());        // 跳转错误页面        modelAndView.setViewName("error");        return modelAndView;    }}配置异常处理器<!--  配置异常处理器  --><bean id="sysExceptionResolver" class="com.cheng.exception.CustomExceptionResolver"/>异常处理在控制层使用 在控制层的 try...catch 中 throw new CustomException(" 系统错误 ")即可

SpringMVC 响应数据与视图

响应数据与视图 返回字符串Controller 方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。    @RequestMapping(value="/hello")    public String sayHello() {        //  跳转到 success 页面        return "success";    }返回 void1、默认会跳转到同 mapping 同名的页面,如@RequestMapping(value="/hello") 默认跳转到 hello 页面,不存在报 4042、已知道 Servlet 原始 API 可以作为控制器中方法的参数,可使用其做转发或重定向    @RequestMapping(value = "/initAdd")    public void initAdd(HttpServletRequest request, HttpServletResponse response) throws            Exception {        System.out.println(" 请求转发或者重定向 ");//  请求转发   转发网址栏地址不变   页面变// request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request,response);//  重定向   跳转网址会产生变化// response.sendRedirect(request.getContextPath()+"/add2.jsp");        response.setCharacterEncoding("UTF-8");        response.setContentType("text/html;charset=UTF-8");//  用 getWriter()直接响应数据        response.getWriter().print(" 你好 ");        return;    }3、使用 SpringMVC 关键字进行转发与重定向 如下重定向与转发不仅仅可以跳页面也能跳到其他 Controller 的 mapping//"forward: 转发的 JSP 路径 ",不走视图解析器了,所以需要编写完整的路径// 转发 @RequestMapping("/delete")    public String delete() throws Exception {// return "forward:/WEB-INF/pages/success.jsp";        return "forward:/user/findAll";    }// 重定向   到本机不需要完整路径    @RequestMapping("/count")    public String count() throws Exception {        return "redirect:/add.jsp";// return "redirect:/user/findAll";    }Model 与 ModelAndViewModelModel 作为参数可调用其 addAttribute 方法添加数据到 request 域,如下:    @RequestMapping(value = "/initUpdate")    public String initUpdate(Model model) {//  模拟从数据库中查询的数据        User user = new User();        user.setUsername(" 张三 ");        model.addAttribute("user", user);        return "update";    }在 jsp 页面可通过 ${requestScope} 或${user.username}调用 request 中内容。ModelAndViewModelAndView 对象是 Spring 提供的一个对象,可以用来调整具体的 JSP 视图。它可以同时传入跳转页面名与数据对象,与上方 Model 功能差不多。只是 Model 将数据存在 Model 中,返回 String 页面名称,一般作为参数,但 ModelAndView 是作为返回值的。    /**     *  返回 ModelAndView 对象     *  可以传入视图的名称(即跳转的页面),还可以传入对象。     *     * @return     * @throws Exception     */    @RequestMapping(value = "/findAll")    public ModelAndView findAll() throws Exception {        ModelAndView mv = new ModelAndView();//  跳转到 list.jsp 的页面        mv.setViewName("list");//  模拟从数据库中查询所有的用户信息        List<User> users = new ArrayList<>();        User user1 = new User();        user1.setUsername(" 张三 ");        user1.setPassword("123");        User user2 = new User();        user2.setUsername(" 赵四 ");        user2.setPassword("456");        users.add(user1);        users.add(user2);//  添加对象        mv.addObject("users", users);        return mv;    }JSP 页面开启 c 标签调用<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>获取集合中值通过 forEach 遍历<c:forEach items="${ users }" var="user">${ user.username }</c:forEach>ResponseBody 返回 json@ResponseBody 注解写在方法上或者方法返回的类型前,或者写在类上或者使用 @RestCotroller 注解 public @ResponseBody Address testJson(@RequestBody String body) {}RequestBody 转对象 上述代码如果 @RequestBody 注解修饰的 String 变量封装成 JavaBean 对象 public @ResponseBody Address testJson(@RequestBody Address address) {} 使用 jackson 添加 jar 包即可,Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换<dependency>    <groupId>com.fasterxml.jackson.core</groupId>    <artifactId>jackson-databind</artifactId>    <version>2.9.0</version></dependency><dependency>    <groupId>com.fasterxml.jackson.core</groupId>    <artifactId>jackson-core</artifactId>    <version>2.9.0</version></dependency><dependency>    <groupId>com.fasterxml.jackson.core</groupId>    <artifactId>jackson-annotations</artifactId>    <version>2.9.0</version></dependency>