Spring学习笔记

传统开发分析

显示层:①负责数据的页面展示 ②联合HTML、CSS、JavaScript    JSP+EL+JSTL      AJAX  +JavaScript +DOM   jQuery+JSON    bootstrap前端框架

控制层:①服务器端验证 ②数据的接收与POJO转换 ③调用业务层 ④进行显示层跳转  Servlet      Struts2.x提供拦截器进行数据验证、提供自动数据类型转换,配置容易

业务层(最需要关注):①负责数据库的打开与关闭 ②调用数据层并且整理数据 ③处理事务    Java原生编码     

数据层:负责数据的CRUD       JDBC原生编码   Hibernate 提升数据库的操作性能与代码简化

JSP+Servlet+JDBC 维护麻烦

Spring简介

Spring本身提供的是一个自己的容器,容器可以负责维持对象的状态或者某一操作的横切。

Spring提供有如下的核心组件:

  ①Beans:Spring对所有Bean对象的管理,包含对象间的关系配置和对象的实例化操作   

  ②Core:包含最底层的开发支持,如依赖注入关系、资源文件的范围,数据类型的转换     

  ③Contex:容器上下文,处理对象的生命周期或者事务   

  ④表达式语言模块:利用SpEL实现表达式语言的操作

AOP:利用切面编程解决所有辅助性操作

Aspect:表示切面编程的语法支持

Spring好处:

①Spring中避免关键字new造成耦合的问题

②Spring本生就是一个工厂,不需要再编写工厂类

③Spring不需要进行明确的引用关系传递,直接通过配置完成

④所有框架可以与Spring整合一起使用

⑤Spring编程=Factory设计模式+Proxy设计模式

控制反转IOC

IOC(Inversion Of Control)

所有对象实例化处理机制不需要关键字new

所有在Spring中配置的<bean>元素表示在容器启动的时候自动进行实例化

依赖注入DI

指的是利用配置文件的关系来决定类之间的引用关系以及数据的设置操作

构造方法、setter、集合注入

①构造方法注入(无用)

②setter注入

<bean id="dept" class="ycit.sth.vo.Dept">
        <property name="deptno" value="10"></property>
        <property name="dname" value="技术部"></property>
</bean>
    <bean id="emp" class="ycit.sth.vo.Emp">
        <property name="empno" value="666"></property>
        <property name="ename" value="张起灵"></property>
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="ycit.sth.vo.Dept">
        <property name="deptno" value="10"></property>
        <property name="dname" value="技术部"></property>
    </bean>

③集合注入

数据的注入:数组、List、Set、Map、Properties

<bean id="company" class="ycit.sth.vo.Company">
        <property name="msg">
            <props>
                <prop key="小哥">张起灵</prop>
                <prop key="天真">吴邪</prop>
            </props>
        </property>
</bean>

p命名空间、自动装配

使用p命名空间     使用 p:属性       p:属性-ref

自动装配   autowire=“byType”

  当有多个进行匹配时,使用推荐选择(primary=true)或者自动退出(autowire-candidate="false")

Bean的其他配置

延迟加载:lazy-init="true"

自定义的初始化和销毁方法操作:

  在类实例化的时候,自动执行一个方法进行特定的初始化调用,当类对象不再需要的时候,自动执行一个销毁方法进行资源的释放。

<bean id="company" class="ycit.sth.vo.Company" init-method="init" destroy-method="destory"></bean>

 Annotation配置注入关系

使用Spring管理避免了工厂类的编写,但问题也同时出现:当出现几百个DAO或Service,这种配置文件方式就不太适合,故使用Annotation配置

①增加命名空间

xmlns:context="http://www.springframework.org/schema/context"

②设置Annotation支持包

<context:annotation-config></context:annotation-config>
<context:component-scan base-package="ycit.sth"></context:component-scan>

表示在ycit.sth包下的所有程序类都支持Annotation的配置,提供三个注解定义    (使用注解定义组件,名称默认情况下就是类名称的结构形式,首字母小写)

@Component:DAO上使用

@Service:Service上使用

@Repository:Action上使用

  @Resource引用关系,表示注入资源

资源访问

Resource操作接口

  读取内存资源:ByteArrayResource子类   构造方法:接收字节数组

  文件读取:FileSystemResource子类    构造方法:接收文件File或者路径

  CLASSPATH读取:ClassPathResource子类 构造方法:接收路径

ResourceLoader接口

  该接口主要进行Resource接口对象实例化使用

  子类:DefaultResourceLoader   通过字符串

  文件读取:“file:路径

  CLASSPATH读取:“classpath:路径

  网络读取:“http://路径

ResourceLoader loader=new DefaultResourceLoader();
Resource resource=loader.getResource("file:d:\\logo.jpg");
System.out.println("数据长度:"+resource.contentLength());
Scanner scan=new Scanner(resource.getInputStream());
scan.useDelimiter("\n");
while (scan.hasNext()){
    System.out.println(scan.next());
}

为了解决Resource与ResourceLoader的操作耦合问题,利用注入操作模式,使ResourceLoader消失

所以,利用Spring读取外部文件资源要比直接使用IO操作更加容易

路径通配符

shiro笔记

表达式语言

SpEL(Spring Element Language) ,类似于JSP学到的EL

自定义分隔符:任何的表达式组成之中一定会包含相应的边界形式,在JSP中“${”作为边界开始,"}"作为边界结束     操作类ParseContext

public class TestELSimple {
    public static void main(String[] args) {
        //1.定义要操作的表达式
        String pstr="#[1+2]";
        //2.定义表达式解析器
        ExpressionParser parser=new SpelExpressionParser();
        //3.使用特定的解析器来处理指定的字符串操作
        Expression exp=parser.parseExpression(pstr, new ParserContext() {
            @Override
            public boolean isTemplate() {  //是否使用模板
                return true;
            }
            @Override
            public String getExpressionPrefix() {
                return "#[";
            }
            @Override
            public String getExpressionSuffix() {
                return "]";
            }
        });
        //4.定义相关环境属性
        EvaluationContext context=new StandardEvaluationContext();
        System.out.println(exp.getValue(context));
    }
}

基本表达式

字面表达式:字符串(注意转义)、数值型、布尔型、null型

数学表达式:四则运算、求模(%  MOD)、幂运算^ 、除法(/  DIV)

关系表达式:(=  EQ )  (!=  NQ)  (>  GT)   (>=   GE)      (<  LT)    (<=  LE)       区间  10  BETWEEN {5,20}

逻辑表达式:  (&&  AND)    (||   OR)    (!    NOT)

字符串表达式+     取索引[1]     replaceAll   Spring类的方法

三目运算符   正则运算   括号表达式

Class类型表达式

取得Class对象 T(String)       

静态属性    T(Integer).MAX_VALUE

静态方法     T(Integer).parseInt('666')

实例化对象   new java.util.Date()

instanceof   'hello' instanceof T(String)

变量操作

ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("#myvar");
EvaluationContext context=new StandardEvaluationContext();
context.setVariable("myvar","小哥");
System.out.println(exp.getValue(context));
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("#root");
EvaluationContext context=new StandardEvaluationContext("张起灵");
System.out.println(exp.getValue(context));

 集合表达式(List、Set、Map)  

Spring认为数组与List是等价的,利用{内容,内容,.......}形式完成    空List 就直接{}    也可以使用索引     用=进行修改

ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("{10,20,30}[1]");
EvaluationContext context=new StandardEvaluationContext();
System.out.println(exp.getValue(context));
输出结果:20
Map<String ,String> map=new HashMap<String,String>();
map.put("小花","解雨臣");
map.put("小哥","张起灵");
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("#data['小花']");
EvaluationContext context=new StandardEvaluationContext();
context.setVariable("data",map);
System.out.println(exp.getValue(context));
输出结果:解雨臣
Expression exp=parser.parseExpression("#data.![#this.key+'-'+#this.value]");

输出结果:[小花-解雨臣, 小哥-张起灵]   处理完map变为新的List

数据的筛选操作支持:包含String的方法比如contains()

Expression exp=parser.parseExpression("#data.?[#this.key=='小哥']");
输出结果:{小哥=张起灵}

将表达式应用在配置文件  ({}这个为表达式分界符)

<bean id="str" class="java.lang.String" >
  <constructor-arg value="helloworld"></constructor-arg>
</bean>
<bean id="msg" class="ycit.sth.vo.Message" >
  <property name="msg" value="#{str.substring(0,5)+'java'}"></property>
</bean>
输出结果:hellojava

Spring的字符串支持很棒,利用表达式可以简化代码的编写。

AOP

AOP简介

Spring两个核心组成:IOC&DI、AOP   最大用途在于事务处理

AOP面向方面的编程,意思是将不同的切入点代码单独定义,而后组织在一个程序网上

Spring通知形式:

①前置通知(BeforeAdvice):在操作执行之前处理

②后置通知(AfterAdvice):在操作执行之后处理

  后置返回通知(AfterReturningAdvice):负责处理返回结果的时候进行拦截

  后置异常通知(AfterThrowingAdvice):当出现异常的时候进行拦截

  后置最终通知(AfterFinallyAdvice):不管是否出现异常都会执行

③环绕通知(AroundAdvice):在具体操作执行之前、之后、异常出现处理等地方任意编写    一个方法处理所有操作

AOP初步实现

@Component
public class ServiceAspect {
    public void serviceBefore(){
        System.out.println("【AOP切面】执行日志记录操作");
    }
    public void serviceAfter(){
        System.out.println("【AOP切面】执行事务处理操作");
    }
}

开启切面,引入aop命名空间

xmlns:aop="http://www.springframework.org/schema/aop"

定义应用切面applicationContext.xml

<aop:config>
        <!--    首先需要定义程序的切入点    表达式语言-->
        <aop:pointcut id="pointcut" expression="execution(* ycit.sth..*.*(..)))"/>
        <!--    定义要使用的面向方面的处理类    -->
        <aop:aspect ref="serviceAspect">
            <aop:before method="serviceBefore" pointcut-ref="pointcut"></aop:before>
            <aop:after method="serviceAfter" pointcut="execution(* ycit.sth..*.*(..)))"></aop:after>
        </aop:aspect>
</aop:config>

此时业务层只出现与业务层核心操作有关的功能代码,所有的辅助功能以切面的形式出现。

 AspectJ定义的切入点操作语法,语法结构如下:execution(修饰符匹配 返回值类型 操作类型匹配 名称匹配(参数匹配)抛出异常匹配)

修饰符:public 、private   一般为public 可省略

返回值:* 表示返回任意类型

名称匹配:ycit.sth..*.*  表示具体要使用此切面的程序类   ..表示子包    *.*表示任意类的任意方法

方法参数:(..)   其中..表示任意匹配多个参数,*表示任意匹配一个参数

AOP深入操作

<aop:config>
        <!--    首先需要定义程序的切入点    表达式语言-->
        <aop:pointcut id="pointcut" expression="execution(* ycit.sth..*.*(..)) and args(vo))"/>
        <!--    定义要使用的面向方面的处理类    -->
        <aop:aspect ref="serviceAspect">
            <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"></aop:before>
            <aop:after method="serviceAfter" pointcut="execution(* ycit.sth..*.*(..)))"></aop:after>
            <aop:after-returning method="serviceAfterReturning" pointcut="execution(* ycit.sth..*.*(..)))" returning="haha" arg-names="haha"></aop:after-returning>
            <aop:after-throwing method="serviceAfterException" pointcut="execution(* ycit.sth..*.*(..)))" arg-names="e" throwing="e"></aop:after-throwing>
            <aop:around method="serviceAround" pointcut="execution(* ycit.sth..*.*(..)))"></aop:around>
        </aop:aspect>
</aop:config>
public class ServiceAspect {
    public void serviceBefore(){
        System.out.println("【AOP切面】执行日志记录操作");
    }

    public void  serviceBefore2(Object arg){
        System.out.println("【AOP切面】执行增加前的操作 参数="+arg);
    }
    public void serviceAfter(){
        System.out.println("【AOP切面】执行事务处理操作");
    }
    public void serviceAfterReturning(Object val){   //表示操作结果
        System.out.println("【AOP切面】操作完成,返回结果"+val);
    }
    public void serviceAfterException(Exception exp){  //操作结果出现异常
        System.out.println("【AOP切面】操作出现异常,"+exp);
    }
    public Object serviceAround(ProceedingJoinPoint point) throws Throwable {
        System.out.println("【AOP切面】数据层方法调用之前,参数:"+ Arrays.toString(point.getArgs()));
        Member vo=new Member();
        vo.setMid("十年之约");
        vo.setName("长白山");
        Object retVal=point.proceed(new Object[]{vo});//调用具体操作
        System.out.println("【AOP切面】数据层方法调用之后,返回值"+retVal);
        return true;
    }
}

基于Annotation配置AOP

打开AOP的Annotation支持

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

编写所需要的Annotation

@Component
@Aspect
public class ServiceAspect {
    @Before(value = "execution(* ycit.sth..*.*(..)))")
    public void serviceBefore(){
        System.out.println("【AOP切面】执行日志记录操作");
    }
    @Before(value = "execution(* ycit.sth..*.*(..))  && args(arg))",argNames = "arg")
    public void  serviceBefore2(Object arg){
        System.out.println("【AOP切面】执行增加前的操作 参数="+arg);
    }
    @After(value = "execution(* ycit.sth..*.*(..)))")
    public void serviceAfter(){
        System.out.println("【AOP切面】执行事务处理操作");
    }
    @AfterReturning(value = "execution(* ycit.sth..*.*(..)))",argNames = "val", returning = "val")
    public void serviceAfterReturning(Object val){   //表示操作结果
        System.out.println("【AOP切面】操作完成,返回结果"+val);
    }
    @AfterThrowing(value = "execution(* ycit.sth..*.*(..)))",argNames = "exp", throwing = "exp")
    public void serviceAfterException(Exception exp){  //操作结果出现异常
        System.out.println("【AOP切面】操作出现异常,"+exp);
    }

    @Around(value = "execution(* ycit.sth..*.*(..)))")
    public Object serviceAround(ProceedingJoinPoint point) throws Throwable {
        System.out.println("【AOP切面】数据层方法调用之前,参数:"+ Arrays.toString(point.getArgs()));
        Member vo=new Member();
        vo.setMid("十年之约");
        vo.setName("长白山");
        Object retVal=point.proceed(new Object[]{vo});//调用具体操作
        System.out.println("【AOP切面】数据层方法调用之后,返回值"+retVal);
        return true;
    }
}

JDBC操作模板

传统JDBC代码简单,不涉及复杂的对象操作,性能最高,但代码冗余度高,用户需要手工进行事务的处理,出现异常,用户需要自己处理。

Spring中JdbcTemplate操作代码简单,不脱离JDBC形式 ,对JDBC轻度包装,但与重度包装的Hibernate不同(Mybatis中度包装),不够智能,处理返回结果不能自动转化为vo类。

连接数据库

  数据库连接使用的操作类DriverManagerDataSource    (实际开发不会使用)

数据库的CRUD操作

  类JdbcTemplate

@Component
public class NewsDAOImpl implements INewsDAO {
    private JdbcTemplate jt;
    @Autowired       //自动根据匹配类型注入所需要的数据
    public NewsDAOImpl(JdbcTemplate jt){
        this.jt=jt;
    }
    @Override
    public boolean doCreate(News vo) throws Exception {
        String sql="INSERT INTO news(title,pubdate,content) VALUES(?,?,?)";
        int count=jt.update(sql,vo.getTitle(),vo.getPubdate(),vo.getContent());
        return count>0;
    }
}
  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/springdb?serverTimezone=UTC"></property>
        <property name="username" value="root"></property>
        <property name="password" value="mysqladmin"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
  </bean>
public class TestSpring {
    public static void main(String[] args) throws Exception{
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        INewsDAO dao=ctx.getBean("newsDAOImpl",INewsDAO.class);
        News vo=new News();
        vo.setTitle("终极笔记");
        vo.setContent("长白山十年之约");
        vo.setPubdate(new Date());
        System.out.println(dao.doCreate(vo));
    }
}

数据库连接池C3p0

建立database.properties文件保存与数据库有关的连接信息

在applicationContext.xml文件中取得配置内容 (注:先设置一个连接,项目上线以后在设置多个连接)

<!--在本程序中设置要导入的资源文件路径,直接通过classpath加载    -->
    <context:property-placeholder location="classpath:database.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${db.driver}"></property>
        <property name="jdbcUrl" value="${db.url}"></property>
        <property name="user" value="${db.user}"></property>
        <property name="password" value="${db.password}"></property>
        <property name="maxPoolSize" value="${pool.max}"></property>   <!--最大连接数-->
        <property name="initialPoolSize" value="${pool.init}"></property>  <!--初始化连接数-->
        <property name="minPoolSize" value="${pool.min}"></property>  <!--最小维持连接数-->
        <property name="maxIdleTime" value="${pool.idle}"></property>  <!--最大等待连接-->
     </bean>

JdbcDAOSupport支持类

   前面是直接利用JdbcTemplate进行数据库的操作(自动注入过程),但很少使用,还一种方式,让DAO实现子类既实现DAO接口,又去继承一个JdbcDAOSupport的抽象类,负责数据库的关闭

@Component
public class NewsDAOImpl extends JdbcDaoSupport implements INewsDAO {
    @Autowired       //自动根据匹配类型注入所需要的数据
    public NewsDAOImpl(JdbcTemplate jt){
        super.setJdbcTemplate(jt);
    }
    @Override
    public boolean doCreate(News vo) throws Exception {
        String sql="INSERT INTO news(title,pubdate,content) VALUES(?,?,?)";
        int count=super.getJdbcTemplate().update(sql,vo.getTitle(),vo.getPubdate(),vo.getContent());
        return count>0;
    }
}

Spring MVC

struts2.x优点:提供拦截器操作;直接使用File类作为文件上传操作;所有的配置在struts.xml里面实现;方便与Spring进行整合;提供各种数据类型的转换操作

struts2.x缺点:为了接收数据,定义许多类属性;

SpringMVC在struts2.x基础上保留转换器、拦截器,同时又使用更加简化的处理方式来处理用户请求参数的接收。

Spring MVC的配置

修改ApplicationContex.xml:

<!--定义Spring MVC的处理    -->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler></mvc:default-servlet-handler>

配置 web.xml文件   (struts2.x利用过滤器进行Action的行为触发,Spring  MVC 所有的控制器的处理依然使用Servlet完成)

  <!-- 负责整个Spring容器启动   -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 配置SpringMVC要使用的控制器   -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>

http://localhost:8080/SpringMVCProject_war_exploded/pages/back/message/hello_demo.action?mid=666&title=张起灵&type.title=终极笔记

地址分析:              表示Action的父路径                        配置的方法路径                        Message对象的组成

最大的特点:不需要类属性来接收参数,所有的接收参数放在业务方法上,避免了实例化问题

ModelAndView类 

无参构造    传跳转路径地址

通过 addObject方法向前端页面传属性

@Controller   //定义一个控制器
@RequestMapping("pages/back/message/*")    //整体访问路径
public class MessageAction {
    @RequestMapping("hello_demo")     //为整个demo方法定义映射子路径,既支持get又支持post
    public ModelAndView demo(Message msg){
        ModelAndView mav=new ModelAndView("/pages/forward.jsp");   //也可以通过资源文件读取
        mav.addObject("msg","未来可期");
        mav.addObject("url","/index.jsp");
        System.out.println(msg);
        return mav;
    }
}

Spring MVC 避免了复杂的跳转路径的配置

注:项目出现中文乱码问题,两种解决方式:

①建立一个过滤器解决提交的乱码

②直接使用Spring提供好的过滤器    CharacterEncodingFilter

<!--增加Spring编码过滤器的配置    -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

后台参数名称可以与地址参数名称不同,并且可以设置默认值,这个对于分页有好处   

   @RequestParam(value = "paramids",defaultValue = "0"

Spring帮助用户解决了参数是否重复的判断和参数类型的自动转换操作

利用Spring MVC实现CRUD操作

MessageAction.java其中对于前端涉及到日期问题要注意,就必须明确定义一个转换器

@Controller   //定义一个控制器
@RequestMapping("pages/message/*")    //整体访问路径
public class MessageAction {
    @Resource
    private IMessageService messageService;
    @Resource
    private MessageSource messageSource;
    @RequestMapping("message_insert")
    public ModelAndView insert(Message msg){
        ModelAndView mav=new ModelAndView("/pages/forword.jsp");
        try {
            System.out.println(this.messageService.insert(msg));
        } catch (Exception e) {
            e.printStackTrace();
        }
        mav.addObject("msg","消息添加成功!");
        mav.addObject("url","/pages/message/message_add.jsp");
        return mav;
    }
    @RequestMapping("message_insertPre")
    public ModelAndView insertPre(){
        System.out.println("属性内容:"+this.messageSource.getMessage("info.msg",null, Locale.getDefault()));
        ModelAndView mav=new ModelAndView("/message/message_add");
        return mav;
    }
    @RequestMapping("message_update")
    public ModelAndView update(Message msg){
        ModelAndView mav=new ModelAndView("/pages/forword.jsp");
        try {
            System.out.println(messageService.update(msg));
        } catch (Exception e) {
            e.printStackTrace();
        }
        mav.addObject("msg","消息修改成功!");
        mav.addObject("url","/index.jsp");
        return mav;
    }
    @RequestMapping("message_delete")
    public ModelAndView delete(@RequestParam(value = "paramids",defaultValue = "0") String ids){
        ModelAndView mav=new ModelAndView("/pages/forword.jsp");
        Set<Integer> set=new HashSet<Integer>();
        String result[]=ids.split("\\|");
        for (int i=0;i<result.length;i++){
            set.add(Integer.parseInt(result[i]));
        }
        try {
            System.out.println(messageService.delete(set));
        } catch (Exception e) {
            e.printStackTrace();
        }
        mav.addObject("msg","消息删除成功!");
        mav.addObject("url","/index.jsp");
        return mav;
    }
    @RequestMapping("message_get")
    public ModelAndView get(int mid){
        ModelAndView mav=new ModelAndView("/pages/forword.jsp");
        try {
            System.out.println(messageService.get(mid));
        } catch (Exception e) {
            e.printStackTrace();
        }
        mav.addObject("msg","消息查询成功!");
        mav.addObject("url","/index.jsp");
        return mav;
    }
    @RequestMapping("message_list")
    public ModelAndView list(String col,String kw,int cp,int ls){
        ModelAndView mav=new ModelAndView("/pages/forword.jsp");try {
            System.out.println(messageService.list(col,kw,cp,ls));
        } catch (Exception e) {
            e.printStackTrace();
        }
        mav.addObject("msg","消息修改成功!");
        mav.addObject("url","/index.jsp");
        return mav;
    }
    @InitBinder
    public void initBinder(WebDataBinder binder){//进行web数据的转换绑定
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        //注册一个专门的日期转换器的操作类,并且允许输入的数据为空
        binder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,true));
    }
}

 

内置对象

四个内置对象:ServletContext、HttpServletRequest、HttpServletResponse、HttpSession

得到request就能得到application和session

定义安全访问

在整个WEB项目里面,放在WEB-INF目录下是最安全的

在applicationContext.xml进行配置      InternalResourceViewResolver   

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
</bean>

这样,使用ModelAndView设置跳转路径的时候不需要设置前缀和后缀,简化开发。

资源文件  

Spring同样可以实现国际化的资源读取

要实现资源文件读取,要使用资源文件读取类:ResourceBundleMessageSource

<!--    配置资源读取-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" >
<property name="basenames">
<array>
<value>Messages</value>
<value>Pages</value>
</array>
</property>
<property name="defaultEncoding" value="UTF-8"/>
<property name="useCodeAsDefaultMessage" value="true" />
</bean>

在需要它的Action上使用依赖注入的方式进行对象的设置(@Resource)

【注】IDEA *.properties默认编码为GBK,在setting里面file encoding进行修改,改为UTF-8。  

文件上传

使用FileUpload上传组件

上传文件的处理类:CommonsMutipartFile

<!--文件上传    -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxInMemorySize" value="2097152"></property>      <!--占用内存的最大值 2M-->
        <property name="maxUploadSize" value="5242880"></property>              <!--上传文件的最大值  5M-->
    </bean>
@Controller
@RequestMapping("/pages/*")
public class UploadAction {
    @RequestMapping("insert")
    public ModelAndView insert(Type type,MultipartFile pic) throws Exception{
        System.out.println("类型名称:"+type.getTitle());
        System.out.println("文件类型:"+pic.getContentType());
        System.out.println("文件大小:"+pic.getSize());
        System.out.println("是否为空:"+pic.isEmpty());
        System.out.println("数据流:"+pic.getInputStream());
        return null;//不跳转
    }
}

如果出现404,500,空指向异常等,将错误信息交给WEB容器处理,以下为web.xml的配置

   <!--    发生异常错误跳转到错误页面-->
    <error-page>
        <error-code>500</error-code>
        <location>/error.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/error.jsp</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.NullPointerException</exception-type>
        <location>/error.jsp</location>
    </error-page>

Spring MVC的做法(两种方式都可以)在applicationContext.xml处理异常信息,处理类SimpleMappingExceptionResolver

<!--    错误信息配置-->
    <bean id="exceptionMapping" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">error</prop>
                <!--上传文件大小超出设定的最大值 ,写error是因为前面的安全配置,文件在/WEB-INF/pages/error.jsp-->
            </props>
        </property>
    </bean>

拦截器

拦截器接口:HandlerInterceptor

定义一个拦截器,实现HandlerInterceptor,里面要实现3个方法,拦截前执行(可以进行规则验证,用到了反射),拦截中执行,以及拦截后执行

<!--    定义拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/pages/**/*.action"/><!--表示 pages目录下的所有action都要假进行拦截-->
            <bean class="ycit.sth.interceptor.MyHandler"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
posted @ 2021-01-31 12:03  我的愿望是如你所愿  阅读(66)  评论(0)    收藏  举报