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>