税友实习日记:一周小结(3)

税友实习日记第三周小结

本周工作内容

  1. 基本完成了所负责的模块的所有内容,开发过程中对于JS方面的知识有了更多充分的理解,比如AJAX也可以同步请求,不仅仅可以用来异步请求,以及使用JS来动态渲染页面和动态获取值。

  2. 对于数据库的操作,发现了Oracle数据库和之前用的MySQL很不一样,不会自动提交,每次在PLSQL中自己进行了增删改之类的操作,没有进行提交事务操作后,在页面中对应的功能会报错,因为Oracle锁表了。

  3. 对于前后端的交互数据,之前没怎么接收过JSON数组进行批处理,这次遇到了,可以在JS中转化为字符串,以JSON形式传输,然后在Controller中拿到后进行转化为一个List集合。

  4. 对于前台传入的日期字符串进行格式化,之前一直以“yyyy-MM-dd”进行转化,这次遇到的不行,因为前端传入的字符串格式不符合此规则,遇到的是这样的,“The Jun 06 1985 00:00:00 GMT+0800 (中国标准时间)”,需要以这种格式格式化“EEE MMM dd yyyy HH:mm:ss ‘GMT’z”转化。

本周开发中的一些小问题

  1. 在一个页面中有两个datagrid时,始终无法给两个datagrid都赋值,第二次赋值会覆盖前一次,即第一次的datagrid会没有数据,始终只有一个datagrid有数据,仍需寻找方法解决。

  2. 在页面中的datagrid中有一个下拉框,下拉框的默认值是空,始终无法将这个默认值改为下拉选项中的一个,仍需等待解决。

总结

这个小模块的开发效率比之前开发那个查询界面快了很对,对于实际项目中的东西也有了更多了解,不像自己开发,想怎么玩怎么玩,需要遵守一些规范,不然你的功能实现不了,理论上你的方法是没毛病的,但是实际上项目中有一些控制或者过滤,导致你的方法会失效,对于JS方面,仍然觉得有好多不足,毕竟之前的想法是前后端分离,不用再写前端的东西,唉,太难了。

接下来就好好消化一下本周学到的东西吧,然后准备8月份去北京的出差,为什么实习生也要出差呐~


以上就是在税友实习的第三周小结,加油,继续努力。

税友实习日记:一周小结(2)

税友实习日记第二周小结

本周工作内容

  1. 做了人员信息的一个超多条件的查询,对于sql的语句拼写以及表之间的关联有了更深入的理解,特别是外关联(left join,right join)。

  2. 准备开发人员任务分配的模块,主要内容是对表的增删改查,没有更多的复杂操作,开发过程中遇到了之前没有遇到的列转行问题,对此又学习到了新东西。

本周开发中的一些小问题

1.在开发人员超多条件的查询过程中遇到的问题

  1. 页面搜索条件框的布局,之前都是自己随意布局,现在需要规范一点,尽量和已有页面的风格一致。

  2. 在js中自定义的代码,需要写入数据库的一个公用表中,以便其他成员用到相同内容时可以统一。

  3. 搜索时需要做些操作,有些数据是内部数据,不该被查出来。

  4. SQL的表关联,一开始对于表的关联没什么认识,都使用的内关联,有些情况应该使用外关联。

  5. 对于登录人员的权限控制,应该只能查询看到自己本级和下级的人。

  6. 参数尽量名字都为param。

  7. 注意别忘了写注释。

2.在人员任务分配的开发中出现的问题

  1. 出现了列转行的问题,即:
    • 通过A表的某一字段去查询B表的某一字段,A与B是一对多关系,可能会查出多条记录,但是想要将他们合并为一条记录,此时需要将B表的字段进行列转行。
    • 解决:使用了Oracle的方法:listadd within group

总结

刚开始进行人员超多条件查询的开发时,还是挺难的,环境配置之类的和自己开发时很不同,一个小小的查询功能做了三天,第一天做了后端代码,踩了一些环境上的坑,第二天做前端页面,痛苦的过程,之前一直没有好好学前端。想着以后不用自己写,第三天写了js。做完了整个功能以后,很有成就感,这过程下来之后,也对开发的大体流程及用到的技术有了初步了解,在对人员任务派发模块的开发过程中,效率有了极大提高。


以上就是在税友实习的第二周小结,加油,继续努力。

故事:小道士与恶魔

故事:小道士与恶魔

小道士准备要下山啦,这次下山是他第一次下山,主要是为了去置办一些东西,香油蜡烛祭品什么的,过几天道观里就要举行二十年一次的祭天活动了,这次祭天很重要,是为了祈求上天保佑大家平安,更是为了制服即将出世的恶魔,二十年一轮回,每过二十年,便是恶魔法力最强大的时候,为了防止恶魔为祸人间,于是道观里每过二十年都会祭天,一方面讨个好彩头,一方面是让大家吃的丰盛点,因为道观里的好多人可能会在这次大战中牺牲。

二十年前的今天,小道士的师父还有小道士的一众师兄师姐们正准备出门,下山去给灾后的百姓疗伤赈灾重建家园,他们刚出门,便发现了门口有一竹篮,竹篮里是一个虚弱的婴儿,脸色惨白似乎只剩下一口气了,于是大家就收养了他,他就成了大家的小道士,转眼间,一晃二十年过去了,小道士也从虚弱的婴儿长成了翩翩公子,虽穿着道士服,却依旧清秀俊郎。

师父看着小道士下山的背景,摸着胡子心事重重,也许这几天会是小道士的天劫,师父一直没有告诉小道士其实小道士刚到道观的时候奄奄一息,无论大家怎么给他取暖喂食,小道士依旧浑身冰冷脸色惨白,似乎马上就要死去了,就在小道士弥留之际,师父决定拿出​长命锁给小道士带上,这长命锁本是恶魔胸前的一块护身符,这护身符有着护主精魄的能力,在二十年的大战中,大家倾尽全力将恶魔打败击退并且将他胸前的护身符也一并打了下来,回来以后将护身符打造成了这长命锁,本是作为下次大战中的一件法宝,可如今看来,只有这长命锁能救小道士了,于是小道士便这样健健康康的生活了二十年,二十年里一次大病小病都没有得过,但是转眼间二十年过去了,长命锁上出现了小小的裂纹,虽然不仔细看根本就看不出来,但是一直想着这件事的师父却早已发现了这丝裂纹,长命锁里残留的法力不多了,小道士体内依旧有着不好的东西,若是小道士平安正常,即使这长命锁中法力尽失,这长命锁也不会出现裂纹,只是成了普通的长命锁罢了,可这裂纹的出现预示着长命锁中残留的法力在与小道士体内的不祥之物抗衡。


小道士蹦蹦跶跶的走在下山路上,第一次下山的他格外兴奋,他用力的呼吸,尝尽道观外每一处空气,那是草的清新味花的芳香味那是大自然的气息,一路上东看西看,有美丽的花草,有可爱的小动物,还有飞翔的鸟儿在头顶在树头叽叽喳喳的叫着,仿佛​在给第一次下山的小道士庆祝唱歌,走着走着,小道士快到山下了,他看着山下,眼睛睁得大大的满眼是光,那是他看过的最美丽的风景,山下的村子里灯火通明,人们有的在唱歌有的在跳舞还有的绝大多数人在看他们唱歌跳舞,村子上空飘满了一束束烟气,那是人们在做好吃的,小道士在山上看着底下热闹的景象听着人们的欢声笑语,觉得世界上最美好的东西就是如此,充满烟火气,比起冷冷清清的道观,村子里简直太好了。

到了村子里,人们见到小道士都会向他问好,问他要不要吃东西要不要喝东西,就连路过青楼姑娘们也都会喊着小道士进去玩,还不要钱的,原来大家是在庆祝二十年前的胜利,每过二十年大家都会盛大的庆祝一次,小道士置办完东西以后便准备回山上了,可是他走着走着,居然在村子里迷路了,最后竟然绕到了别人家里,小道士准备向里面的人问问路,他走进去找人在哪,没想到人是找到了,可那是个正在沐浴的女子,浑身赤裸着,小道士看到女子的那一刻,女子也刚好看到小道士,随着一声尖锐响亮的啊以后,一根结实坚硬的棍子正中小道士的脸正中央,小道士的脸上赫然出现一块长长的长条状红色印记,一阵解释道歉求原谅以后,女子终于原谅了小道士,其实也有着颜值即正义的成分,小道士太帅了,女子决定送小道士上山,毕竟这么帅的帅哥不常见呀,她想多看几眼。

小道士和女子走在上山的路上。

女子:​你这小道士真够不正经的,光天化日之下居然偷看良家妇女洗澡,我的清白都被你毁了呜呜呜呜

小道士:对不起对不起,我我我不是故意的,我当时迷路了,想着找个人问问路,真的不是故意看姑娘你洗澡的,我会负责的,姑娘想我怎样都行​。

女子:那….不如你娶了我吧,按照常理,我都让你看了都没有清白了,你该娶了我。

小道士:这个…这个…

小道士憋红了脸

女子:哎呀哎呀,逗你玩呢,你这小道士可真可爱嘻嘻。

​说完便捏了捏小道士的脸,小道士的脸更红了,女子哈哈大笑。

女子:小道士,这是你第一次下山呀,在村子里都能迷路。

小道士:对呀,这是我第一次下山,给道观祭天置办东西。

女子:哦~这样啊,那你觉得村子好看吗?

小道士特别兴奋:好看!!!!!这是我看过的最好看最美好的景象,大家都很开心,村子里也很热闹,充满了烟火气,我真的太喜欢村子了。

女子坏笑:那以后你多下山呀嘻嘻,我带你玩。

小道士:好呀好呀,等我这次打败恶魔就下山找你玩​。

女子:那就一言为定啦,谁不遵守约定就要被打脑袋。​


小道士和女子在路上说说笑笑的​,天空特别蓝,云特别好看特别白,阳光也很好天气也很好,恍惚之间小道士觉得似乎在哪见过女子,似乎心突然怦怦怦跳的有点快,可还没来得及问,小道士便到道观了,小道士和女子就此分别,带着他们的约定分别。

两天以后,师父带着小道士还有小道士的师兄弟师兄妹们出征讨伐恶魔,在此之前师父还特意叮嘱小道士别太拼命,要注意保护自己,制服恶魔的事交给他们就行了,小道士嘴上答应可心里却没答应,随着东寻西去以后,似乎终于到了地方,小道士在这附近看到了女子,非常开心,向她挥了挥手​打了招呼,可出人意料的是,师父还有师兄弟师兄妹们看到了女子却拔起剑就冲上前向女子杀去,小道士瞬间失了神,他的世界观仿佛崩塌了,女子居然就是恶魔,这不可能,恶魔是残暴凶恶的,和可爱善良美好的女子根本不搭边,小道士愣在了原地,小道士想着和女子的约定,想着好多好多东西,就在他失神的片刻,他看到师父在女子的背后准备刺去,他当时便什么也没想冲向了女子,挡住了师父的那致命一击,此时此刻,只听见啪的一声,长命锁它彻底裂了,小道士奄奄一息的倒在了女子怀里,说道对不起,我不能下山陪你玩了,完成不了约定了,你打我的脑袋吧,说完便昏了过去,女子见此,十分愤怒,她把道士们打的节节败退,恶魔的法力是人类不可匹敌的,好多人都死在了她的手上,当然包括小道士的师父,最后她带着小道士飞到了一个山洞中,道士们紧追着她却不敢进去,她在山洞里用尽了全部法力,将裂了的长命锁变回自己的护身符,将奄奄一息的小道士变回婴儿模样并且受到自己法力的保护,人类有着恶魔法力的保护便不会死去,但是会变的十分寒冷惨白就像快死了一般,由于自己的法力不够保护成年体格的小道士,只能将他变成婴儿了,女子用了幻象骗走了道士们,然后带着婴儿小道士离开了山洞,一个不注意护身符却掉在了洞口地上,女子离开山洞后不久,有一个道士想着来山洞里看看,却在山洞口发现了护身符,然后不久以后他成了道观新的观长,几天以后女子将婴儿小道士放在一个竹篮里,送到了道观门口。

女子回到了村子里休养生息,等待着法力的恢复,这一等就是二十年,二十年一个轮回,二十年只是为了等待一个约定的实现。

在很久很久很久以前,女子还是一个为祸一方的恶魔,却与一个道士相爱了,那道士也不知她是恶魔,他俩约定要在山下的村子里见面玩耍,可是恶魔终究是会被讨伐的,即使她不再作乱,那个道士为她挡下了致命一击,临死前说道​我多想再见你一眼和你在村子里见面玩耍,然后就嗝屁了,女子勃然大怒又十分不舍,大战以后想尽一切办法将道士救了回来,只不过成了婴儿,为了实现这个约定他将道士送回了道观,自己也需要时间恢复法力,这样一次又一次,每次都是二十年才会有一个结果,可是每次等了好久以后的结果都是一样的,女子与道士的约定始终没有兑现,慢慢的女子从那个野蛮的恶魔变成了一个可爱小女子的性格,但是女子依旧只能一次次看着道士死去变成婴儿然后长大,这其中的痛苦是常人不能体会的。


也许这就是执念,女子一次次的重蹈覆辙是执念,道士一次次的为女子挡下致命一击也是执念,​执念这东西就是这样,就算知道后果就算会失败可还是会一次次尝试,因为心有不甘,因为特别特别希望执念能成真,因为太遗憾。

SSM整合

SSM整合

整合思路

  • 首先对于每一个框架都搭建好环境且可以正常运行
  • 然后再对三个框架进行整合
  • Spring整合SpringMVC和MyBatis两个框架
    NZVf8x.md.png

整合方式选择

  • 这里的整合方式选择XML+注解
  1. SpringMVC:

    • web.xml:
      • 前端控制器
      • 拦截器
    • 配置文件配置:
      • 要扫描的包
      • 视图解析器
      • 忽略过滤器的文件
      • 开启注解
    • 注解配置:
      • 对应的控制器注解
  2. Spring:

    • 配置文件配置:
      • 要扫描的包
    • 注解配置:
      • 对应的业务层注解及依赖注入
  3. MyBatis:

    • 配置文件配置:(在整合后可以不需要这个配置文件)
      • 主配置文件
      • 配置环境(连接数据库相关)
      • 配置文件(动态代理的dao在哪)
    • 注解配置:
      • 对应的持久层注解及sql语句

整合:

  1. Spring整合SpringMVC
    NZVOPI.md.png

    • 在web.xml配置监听器,一旦服务器启动就加载Spring的配置文件,将相关的bean对象注入ioc容器。

      <!-- 配置前监听器加载Spring配置文件,默认只加载WEB-INF下的applicationContext.xml文件 -->
      <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      <!-- 设置配置文件的路径 -->
      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:applicationContext.xml</param-value>
      </context-param>
  2. Spring整合MyBatis

    • 在Spring的配置文件中配置

      1. 配置连接池

        <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value=" "/>
            <property name="url" value=" "/>
            <property name="username" value=" "/>
            <property name="password" value=" "/>
        </bean>
      2. 配置SqlSessionFactory对象

        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="druidDataSource"/>
        </bean>
      3. 配置dao接口所在的包

        <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="ssm.dao"/>
        </bean>
    • 对于增删改的需求还需要再Spring的配置文件中声明事务

      1. 配置事务管理器

        <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="druidDataSource"/>
        </bean>
      2. 配置事务通知

        <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
            <tx:attributes>
                <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
                <tx:method name="*" read-only="false" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
      3. 配置AOP增强

        <aop:config>
            <aop:advisor advice-ref="txAdvice" pointcut="execution(* ssm.service.impl.*.*(..))"/>
        </aop:config>

SpringMVC二

SpringMVC二

响应数据和结果视图

1. 返回值为字符串

  • controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
  • 如:return "success";就会在xml文件中视图解析器配置的文件夹下去找对于的文件跳转。

2. 没有返回值(void)

  • 可以使用Servlet原始API作为控制器中方法的参数,用request进行请求转发或者用response进行重定向。

3. ModelAndView

  • ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值。
  • 可以创建一个ModelAndView对象,然后写入响应数据及要跳转的视图名,最后返回此对象。
  • 这种方法走的也是视图解析器。

ResponseBody 响应 json 数据

  • @ResponseBody
  • 作用:
    • 该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如:json,xml 等,通过 Response 响应给客户端。
  • 注意:Springmvc 默认用MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入jackson 的包。

SpringMVC 实现文件上传

必要前提

  1. form 表单的 enctype 取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)
    • enctype:是表单请求正文的类型
  2. method 属性取值必须是 Post
  3. 提供一个文件选择域<input type=”file” />
  • 借助第三方组件:Commons-fileupload
    commons-io

无论使用何种方式上传都需要配置文件解析器

<!-- 配置文件解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"/>
</bean>
  • 注意:文件上传的解析器 id 是固定的,不能起别的名称,否则无法实现请求参数的绑定。

传统方式的文件上传

    public String fileUpLoad1(HttpServletRequest request) throws Exception {
    // 使用fileupload组件完成文件上传
    // 上传的位置
    String path = request.getSession().getServletContext().getRealPath("/upload/");
    // 判断,该路径是否存在
    File file = new File(path);
    if (!file.exists()) {
        // 创建该文件夹
        file.mkdirs();
    }

    // 解析request对象,获取上传文件项
    DiskFileItemFactory df = new DiskFileItemFactory();
    ServletFileUpload servletFileUpload = new ServletFileUpload(df);
    // 解析request
    List<FileItem> items = servletFileUpload.parseRequest(request);
    // 遍历
    for (FileItem item : items) {
        // 进行判断,当前item对象是否是上传文件项
        if (item.isFormField()) {
            // 说明普通表单向
        } else {
            // 说明上传文件项
            // 获取上传文件的名称
            String filename = item.getName();
            // 把文件的名称设置唯一值,uuid
            String uuid = UUID.randomUUID().toString().replace("-", "");
            filename = uuid + "_" + filename;
            // 完成文件上传
            item.write(new File(file, filename));
            // 删除临时文件
            item.delete();
        }
    }

    return "success";
}

SpringMVC方式文件上传

    public String fileUpLoad2(HttpServletRequest request, MultipartFile upload) throws Exception {
    // 使用fileupload组件完成文件上传
    // 上传的位置
    String path = request.getSession().getServletContext().getRealPath("/upload/");
    // 判断,该路径是否存在
    File file = new File(path);
    if (!file.exists()) {
        // 创建该文件夹
        file.mkdirs();
    }

    // 说明上传文件项
    // 获取上传文件的名称
    String filename = upload.getOriginalFilename();
    // 把文件的名称设置唯一值,uuid
    String uuid = UUID.randomUUID().toString().replace("-", "");
    filename = uuid + "_" + filename;
    // 完成文件上传
    upload.transferTo(new File(path, filename));

    return "success";
}
  • 原理:
    NEqFxK.md.png

SpringMVC跨服务器方式文件上传

public String fileUpLoad3(MultipartFile upload) throws Exception {

    //定义上传服务器路径
    String path = "服务器地址/上传的文件夹/";

    // 说明上传文件项
    // 获取上传文件的名称
    String filename = upload.getOriginalFilename();
    // 把文件的名称设置唯一值,uuid
    String uuid = UUID.randomUUID().toString().replace("-", "");
    filename = uuid + "_" + filename;

    //创建客户端对象
    Client client = Client.create();
    //和图片服务器进行连接
    WebResource webResource = client.resource(path + filename);
    //上传文件
    webResource.put(upload.getBytes());

    return "success";
}
  • 原理:
    NEqMGt.md.png

SpringMVC 中的异常处理

  • 系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

  • 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理,如下图:
    NEqzy8.md.png

  • 步骤:

    1. 定义一个自己的异常类和错误页面
    2. 自定义异常处理器
    3. 配置异常处理器
  • 自定义异常处理器时必须实现HandlerExceptionResolver接口

  • 自定义完异常处理器后需要在配置文件中注入依赖,即用一个bean注册一下


SpringMVC 中的拦截器

NEOHPA.md.png

  • Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。

  • 拦截器与过滤器的不同:

    • 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
    • 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
    • 过滤器在 url-pattern 中配置了/之后,可以*对所有要访问的资源拦截。**
    • 拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
  • 我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。

  • 拦截器中的方法:

    1. preHandle,在进入具体的控制强之前执行,返回值为一个布尔值,为true则放行,为false则不放行,在此方法中可以跳转到另一个页面。
    2. postHandle,在进入具体的控制强之后执行,没有返回值,在此方法中可以跳转到另一个页面。
    3. afterCompletion,在进入控制器最后返回页面之后执行,在此方法中不可以跳转到另一个页面。
  • 自定义拦截器之后需要在配置文件中配置拦截器

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            //配置拦截的控制强路径
            <mvc:mapping path="/user/*"/>
            //配置具体的拦截器类
            <bean class="springmvc2interceptor.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

SpringMVC一

SpringMVC一

SpringMVC是什么?

  • SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring的 Spring MVC 框架或集成其他 MVC 开发框架。
  • SpringMVC 已经成为目前最主流的 MVC 框架之一。
  • 它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。

SpringMVC 和 Struts2 的优略分析

  • 共同点:
    1. 它们都是表现层框架,都是基于 MVC 模型编写的。
    2. 它们的底层都离不开原始 ServletAPI。
    3. 它们处理请求的机制都是一个核心控制器。
  • 区别:
    1. Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
    2. Spring MVC 是基于方法设计的,而 Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
    3. Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便

基本步骤

  1. 配置一个前端控制器

    <servlet>
        <servlet-name>SpringMVCDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 配置初始化参数,用于读取 SpringMVC 的配置文件 --> 
            <init-param> 
                <param-name>contextConfigLocation</param-name> 
                <param-value>classpath:SpringMVC.xml</param-value>
            </init-param>
            <!-- 配置 servlet 的对象的创建时间点:应用加载时创建。取值只能是非 0 正整数,表示启动顺序 --> 
            <load-on-startup>1</load-on-startup>
    </servlet> 
    <servlet-mapping> 
        <servlet-name>SpringMVCDispatcherServlet</servlet-name> 
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  2. 配置视图解析器

    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
  3. 配置对应的controller类

  4. 在对应的html或者jsp中进行使用


SpringMVC中的一些组件

  1. DispatcherServlet:前端控制器

    • 用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
  2. HandlerMapping:处理器映射器

    • HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
  3. Handler:处理器

    • 它就是我们开发中要编写的具体业务控制器。由DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
  4. HandlAdapter:处理器适配器

    • 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  5. View Resolver:视图解析器

    • View Resolver 负责将处理结果生成 View 视图,ViewResolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。

mvc:annotation-driven说明

  • 在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
  • 使 用<mvc:annotation-driven>自动加载处理映射器和
    处理适配器,可用在SpringMVC.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。

RequestMapping注解

  • 作用:用于建立请求 URL 和处理请求方法之间的对应关系。
  • 出现位置:
    • 类上:
      • 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
      • 它出现的目的是为了使我们的 URL 可以按照模块化管理:
        • 例如:
        • 账户模块:
          • /account/add
          • /account/update
          • /account/delete
    • 方法上:
      • 请求 URL 的第二级访问目录。
  • 属性:
    • value:用于指定请求的 URL。它和 path 属性的作用是一样的。
    • method:用于指定请求的方式。POST、GET…..
    • params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样。
      • 例如:
        • params = {“accountName”},表示请求参数必须有accountName
        • params = {“moeny!100”},表示请求参数中 money 不能是 100。
    • headers:用于指定限制请求消息头的条件。

请求参数的绑定

支持的数据类型

  • 基本类型参数:
    • 包括基本类型和 String 类型
  • POJO 类型参数:
    • 包括实体类,以及关联的实体类
  • 数组和集合类型参数:
    • 包括 List 结构和 Map 结构的集合(包括数组)

使用要求

  • 如果是基本类型或者 String 类型:
    • 要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
  • 如果是 POJO 类型,或者它的关联对象:
    • 要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
  • 如果是集合类型,有两种方式:
    1. 第一种:
      • 要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
      • 给 List 集合中的元素赋值,使用下标。
      • 给 Map 集合中的元素赋值,使用键值对。
    2. 第二种:
      • 接收的请求参数是 json 格式数据。需要借助一个注解实现。

编写过滤器解决请求参数乱码的问题

<filter>
    <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 可以在springmvc的配置文件中可以配置,静态资源不过滤:

    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/scripts/" mapping="/javascript/**"/>

自定义类型转换器

  • 对于某些前端提交的数据SpringMVC自动转换可能会失败,比如日期类型,2020/10/10这样是可以转换的,但是2020-10-10这样就不行了,这时候就需要自定义类型转换器。

  • 步骤:

    1. 定义一个类,实现Converter接口,该接口有两个泛型S和T,S表示接受的类型,T表示目标类型。

    2. 实现类型转换的方法

    3. 在springMVC配置文件中配置类型转换器。

      <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
          <property name="converters">
              <set>
                  <bean class="Utils.DateConvert"></bean>
              </set>
          </property>
      </bean>
    4. annotation-driven标签中引用配置的类型转换服务,<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>


常用注解

  1. RequestParam

    • 作用:
      • 把请求中指定名称的参数给控制器中的形参赋值。当形参名与请求参数中的名字不一样时可以使用这个注解进行赋值。
    • 属性:
      • value:请求参数中的名称。
      • required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
  2. RequestBody

    • 作用:
      • 用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。
      • get 请求方式不适用。
    • 属性:
      • required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。
  3. PathVaribale

    • 作用:

      • 用于绑定 url 中的占位符。例如:请求url中 /delete/{id},这个{id}就是 url 占位符。
      • url支持占位符是springmvc支持rest风格URL的一个重要标志。
    • 属性:

      • value:用于指定 url 中占位符名称。
      • required:是否必须提供占位符。
    • 例如:

      @RequestMapping("/usePathVariable/{id}")
      public String usePathVariable(@PathVariable("id") Integer id){
          System.out.println(id);
          return "success"; 
      }
      
      当访问/usePathVariable/10时,id就是传进来的10。
  4. RequestHeader

    • 作用:
      • 用于获取请求消息头。
    • 属性:
      • value:提供消息头名称
      • required:是否必须有此消息头
    • 注:
      • 在实际开发中一般不怎么用
  5. CookieValue

    • 作用:
      • 用于把指定 cookie 名称的值传入控制器方法参数。
    • 属性:
      • value:指定 cookie 的名称。
      • required:是否必须有此 cookie。
  6. ModelAttribute

    • 作用:
      • 该注解可以用于修饰方法和参数。
        • 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
      • 出现在参数上,获取指定的数据给参数赋值。如:@ModelAttribute("abc")User user
    • 属性:
      • value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
    • 应用场景:
      • 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
  7. SessionAttribute

    • 作用:
      • 用于多次执行控制器方法间的参数共享。如@SessionAttributes(value ={"username","password"},types={Integer.class})
    • 属性:
      • value:用于指定存入的属性名称
      • type:用于指定存入的数据类型。

Spring四

Spring四

关于dao层中实现类的一个问题

  • dao层中的实现类需要一个JdbcTemplate进行增删改查时

    1. 方式一:可以增加一个成员变量,然后在配置文件中进行配置,适用于所有配置方式(xml 和注解都可以),建议与注解配置bean相搭配

    2. 方式二:可以让实现类继承JdbcDaoSupport,这样就不再需要增加成员变量JdbcTemplate及其set方法,可以简化代码,但是此方法只能在配置文件配置bean时搭配使用。


Spring中的事务控制

  • 第一:JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计业务层的事务处理解决方案。

  • 第二:spring 框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-5.0.2.RELEASE.jar中。

  • 第三:spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。

    Spring中事务控制的API介绍

  • PlatformTransactionManager:此接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。

    1. 获取事务状态信息:TransactionStatus getTransaction(TransactionDefinition definition)
    2. 提交事务:void commit(TransactionStatus status)
    3. 回滚事务:void rollback(TransactionStatus status)
    • 在开发中使用它的实现类:
      1. DataSourceTransactionManager:使用 Spring JDBC 或 iBatis 进行持久化数据时使用
      2. HibernateTransactionManager:使用Hibernate 版本进行持久化数据时使用
  • TransactionDefinition:事务的定义信息对象,里面有如下方法

    1. 获取事务对象名称:String getName()
    2. 获取事务隔离级别:int getIsolationLevel()
    3. 获取事务传播行为:int getPropagationBehavior()
      • 事务的传播行为:
        • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
        • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
        • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
        • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
        • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
        • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
        • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。
    4. 获取事务超时时间:int getTimeout()
    5. 获取事务是否只读:boolean isReadOnly()
  • TransactionStatus:是事务具体的运行状态,方法如下

    1. 刷新事务:void flush()
    2. 获取是否存在存储点:boolean hasSavepoint()
    3. 获取事务是否完成:boolean isCompleted()
    4. 获取事务是否为新的事务:boolean isNewTransaction()
    5. 获取事务是否回滚:boolean isRollbackOnly()
    6. 设置事务回滚:void setRollbackOnly()

基于XML的声明式事务控制

  • 步骤:
    1. 配置事务管理器
    2. 配置事务的通知
      • 此时我们需要导入事务的约束tx名称空间和约束,同时也需要aop的使用tx:advice标签配置事务通知
        • 属性:
          • id:给事务通知起一个唯一标识
          • transaction-manager:给事务通知提供一个事务管理器引用
    3. 配置AOP中的通用切入点表达式
    4. 建立事务通知和切入点表达式的对应关系
    5. 配置事务的属性
      • 是在事务的通知tx:advice标签的内部
      • 事务的属性有:
        1. isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
        2. propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
        3. read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
        4. timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
        5. rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
        6. no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。

基于注解的配置方式

  • 步骤:
    1. 配置事务管理器
    2. 开启spring对注解事务的支持
    3. 在需要事务支持的地方使用@Transactional注解,对应的想要配置属性可以在此注解中配置

Spring三

Spring三

AOP

什么是AOP?

  • AOP:全称是 Aspect Oriented Programming 即:面向切面编程
  • 简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。就是不再需要创建一个实体类去给某些类的方法进行增强,只需要将这些增强的代码抽取出来为一个类,然后配置Spring,在使用需要增强方法的时候由Spring自己动态代理的给你增强。

    AOP 的作用及优势

  • 作用:
    • 在程序运行期间,不修改源码对已有方法进行增强。
  • 优势:
    1. 减少重复代码
    2. 提高开发效率
    3. 维护方便

      AOP 的实现方式

      使用动态代理技术。

动态代理

动态代理:

  • 特点:字节码随用随创建,随用随加载

  • 作用:不修改源码的基础上对方法增强

  • 类:

    1. 基于接口的动态代理
    2. 基于子类的动态代理
  • 基于接口的动态代理:

    • 涉及的类:Proxy
    • 提供者:JDK官方
    • 如何创建代理对象:
      • 使用Proxy类中的newProxyInstance方法
      • 创建代理对象的要求:
        • 被代理类最少实现一个接口,如果没有则不能使用
        • newProxyInstance方法的参数:
          1. ClassLoader:类加载器
            • 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
          2. Class[]:字节码数组
            • 它是用于让代理对象和被代理对象有相同方法。固定写法。
          3. InvocationHandler:用于提供增强的代码
            • 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
            • 此接口的实现类都是谁用谁写。
            • 实现此接口时会重写invoke方法,其中的参数proxy代表代理对象的引用,method代表当前执行的方法,args当前执行方法所需的参数,return返回值为和被代理对象方法有相同的返回值.
  • 基于子类的动态代理

    • 涉及的类:Enhancer
    • 提供者:第三方cglib库
    • 如何创建代理对象:
      • 使用Enhancer类中的create方法
      • 创建代理对象的要求:
        • 被代理类不能是最终类
      • create方法的参数:
        1. Class:字节码
          • 它是用于指定被代理对象的字节码。
        2. Callback:用于提供增强的代码
          • 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
          • 此接口的实现类都是谁用谁写。
          • 我们一般写的都是该接口的子接口实现类:MethodInterceptor

AOP的相关术语

  1. Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。就是所有方法。
  2. Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。就是需要动态代理增强的方法。
  3. Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。就是对要增强的方法干什么。
    • 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
      tzjbTK.md.jpg
  4. Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。
  5. Target(目标对象):代理的目标对象。
  6. Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。就是动态代理增强的这个过程。
  7. Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。
  8. Aspect(切面):是切入点和通知(引介)的结合。

Spring中基于XML的AOP配置

  • 配置步骤

    1. 把通知Bean也交给spring来管理
    2. 使用aop:config标签表明开始AOP的配置
    3. 使用aop:aspect标签表明配置切面
      • id属性:是给切面提供一个唯一标识
      • ref属性:是指定通知类bean的Id。
    4. 在aop:aspect标签的内部使用对应标签来配置通知的类型
      • aop:before:表示配置前置通知
        • method属性:用于指定Logger类中哪个方法是前置通知
        • pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
  • 切入点表达式的写法:

    • 关键字:execution(表达式)
    • 表达式:
      • 访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
      • 标准的表达式写法:
        public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
      • 访问修饰符可以省略
        void com.itheima.service.impl.AccountServiceImpl.saveAccount()
      • 返回值可以使用通配符,表示任意返回值
        * com.itheima.service.impl.AccountServiceImpl.saveAccount()
      • 包名可以使用通配符,表示任意包。但是有几级包,就需要写几个.
        `
        ....AccountServiceImpl.saveAccount())`
      • 包名可以使用..表示当前包及其子包
        *..AccountServiceImpl.saveAccount()
      • 类名和方法名都可以使用来实现通配
        `
        ...*()`
      • 参数列表:
        • 可以直接写数据类型:
          • 基本类型直接写名称 int
          • 引用类型写包名.类名的方式 java.lang.String
          • 可以使用通配符表示任意类型,但是必须有参数
          • 可以使用..表示有无参数均可,有参数可以是任意类型
      • 全通配写法:
        * *..*.*(..)
      • 实际开发中切入点表达式的通常写法:
        • 切到业务层实现类下的所有方法
          * com.itheima.service.impl.*.*(..)
  • Spring中基于注解配置环绕通知

  • 问题:

    • 当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
  • 分析:

    • 通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有。
  • 解决:

    • Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
    • 该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
  • spring中的环绕通知:

    • 它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。

Spring中基于注解的AOP配置

  • 首先需要导入关于注解及aop的约束。

  • 步骤:

    1. 在通知类上使用@Aspect注解声明为切面。

    2. 在增强的方法上使用注解配置通知

      1. @Before
        • 作用:把当前方法看成是前置通知。
        • 属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用。
      2. @AfterReturning
        • 作用:把当前方法看成是后置通知。
        • 属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用
      3. @AfterThrowing
        • 作用:把当前方法看成是异常通知。
        • 属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用
      4. @After
        • 作用:把当前方法看成是最终通知。
        • 属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用
      5. @Around
        • 作用:把当前方法看成是环绕通知。
        • 属性:value:用于指定切入点表达式,还可以指定切入点表达式的引用。
    3. 在配置文件中开启对注解AOP的支持

      <aop:aspectj-autoproxy/>
  • 切入点表达式注解,使用@Pointcut

    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    private void pt1() {}
    应用时
    @Before("pt1()")//注意:千万别忘了写括号

Spring二

Spring二

Spring中基于注解进行配置

  • 曾经XML的配置:

    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"
        scope=""  init-method="" destroy-method="">
        <property name=""  value="" | ref=""></property>
    </bean>
    • 用于创建对象的注解

      • 他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的
      1. Component:
        • 作用:用于把当前类对象存入spring容器中
        • 属性:
          • value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
      2. Controller:一般用在表现层
      3. Service:一般用在业务层
      4. Repository:一般用在持久层
        • 以上三个注解他们的作用和属性与Component是一模一样。
        • 他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
    • 用于注入数据的注解

      • 他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
      1. Autowired:
        • 作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
        • 如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
        • 如果Ioc容器中有多个类型匹配时:则需要和Qualifier注解搭配使用。
          • 出现位置:
            • 可以是变量上,也可以是方法上
          • 细节:
            • 在使用注解注入时,set方法就不是必须的了。
      2. Qualifier:
        • 作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以。
        • 属性:
          • value:用于指定注入bean的id。
      3. Resource
        • 作用:直接按照bean的id注入。它可以独立使用
        • 属性:
          • name:用于指定bean的id。
      • 以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
      • 另外,集合类型的注入只能通过XML来实现。
      1. Value
        • 作用:用于注入基本类型和String类型的数据
        • 属性:
          • value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
          • SpEL的写法:${表达式}
    • 用于改变作用范围的注解

      • 他们的作用就和在bean标签中使用scope属性实现的功能是一样的
      1. Scope
        • 作用:用于指定bean的作用范围
        • 属性:
          • value:指定范围的取值。常用取值:singleton prototype
    • 和生命周期相关的注解

      • 他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
      1. PreDestroy
        • 作用:用于指定销毁方法
      2. PostConstruct
        • 作用:用于指定初始化方法
    • 在注解完成后还需要去XML配置,告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为context名称空间和约束中

      <context:component-scan base-package="你的包"></context:component-scan>

完全使用注解进行配置不再需要XML

  • 有一个配置类,它的作用和bean.xml是一样的

    spring中的新注解

  1. Configuration

    • 作用:指定当前类是一个配置类
    • 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
  2. ComponentScan

    • 作用:用于通过注解指定spring在创建容器时要扫描的包
    • 属性:
      • value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
    • 我们使用此注解就等同于在xml中配置了<context:component-scan base-package="com.itheima"></context:component-scan>
  3. Bean

    • 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
    • 属性:
      • name:用于指定bean的id。当不写时,默认值是当前方法的名称
    • 细节:
      • 当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
      • 查找的方式和Autowired注解的作用是一样的
  4. Import

    • 作用:用于导入其他的配置类
    • 属性:
      • value:用于指定其他配置类的字节码。
    • 当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
  5. PropertySource

    • 作用:用于指定properties文件的位置
    • 属性:
    • value:指定文件的名称和路径。
    • 关键字:classpath,表示类路径下

Spring整合Junit

  • Spring整合junit的配置
    1. 导入spring整合junit的jar(坐标)
    2. 使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的@Runwith
    3. 告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
      • @ContextConfiguration
        • locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
        • classes:指定注解类所在地位置
          • 当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上

Spring一

Spring一

什么是Spring?

  • Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以IoC(Inverse Of Control:反转控制AOP(Aspect Oriented Programming:面向切面编程为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。

什么是控制反转-Inversion Of Control?

  • 原本创建对象这一过程对我们来说是主动的,想用什么方式就用什么方式,可以自己new,也可以用工厂创建,而现在我们将创建对象这一过程交给了Spring,我们只是被动接收,这种被动接收的方式获取对象的思想就是控制反转。
  • 作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。

Spring中配置bean

<bean id="  " class="  "></bean>
  • 作用:

    • 用于配置对象让 spring 来创建的。
    • 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
  • 属性:

    1. id:给对象在容器中提供一个唯一标识。用于获取对象。
    2. class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
    3. scope:指定对象的作用范围。
      • singleton :默认值,单例的.
      • prototype :多例的.
      • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
      • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
      • global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.
    4. init-method:指定类中的初始化方法名称。
    5. destroy-method:指定类中销毁方法名称。

作用范围和生命周期

  1. 单例对象:scope=”singleton”

    • 一个应用只有一个对象的实例。它的作用范围就是整个引用。
    • 生命周期:
      • 对象出生:当应用加载,创建容器时,对象就被创建了。
      • 对象活着:只要容器在,对象一直活着。
      • 对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
  2. 多例对象:scope=”prototype”

    • 每次访问对象时,都会重新创建对象实例。
    • 生命周期:
      • 对象出生:当使用对象时,创建新的对象实例。
      • 对象活着:只要对象在使用中,就一直活着。
      • 对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。

实例化 Bean 的三种方式

  1. 第一种方式:使用默认无参构造函数

    • 在默认情况下:它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。

      <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
  2. 第二种方式:spring 管理静态工厂-使用静态工厂的方法创建对象

    <bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="createAccountService"></bean>
  3. 第三种方式:spring 管理实例工厂-使用实例工厂的方法创建对象

    <bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean> 
    <bean id="accountService" factory-bean="instancFactory" factory-method="createAccountService"></bean>

Spring中的容器:用于读取配置文件

  1. ApplicationContext:是BeanFactory接口的子类,只要一读取配置文件,默认情况下就会创建对象。

    • 它的实现类:
      • ClassPathXmlApplicationContext:它是从类的根路径下加载配置文件 推荐使用这种
      • FileSystemXmlApplicationContext:它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
      • AnnotationConfigApplicationContext:当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
  2. BeanFactory:是Spring容器中的顶层接口。什么时候使用什么时候创建对象。


spring 的依赖注入

  • 概念:
    • 依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
    • 我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
    • ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。
    • 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
    • 简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

构造函数注入

  • 就是将需要注入的属性加入到构造函数中。

    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="张三"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg> 
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>
  • constructor-arg

    • 属性:
      1. index:指定参数在构造函数参数列表的索引位置
      2. type:指定参数在构造函数中的数据类型
      3. name:指定参数在构造函数中的名称
      4. value:它能赋的值是基本数据类型和 String 类型
      5. ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
  • 优势:

    • 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
  • 弊端:

    • 改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

set方法注入

  • 就是将需要注入的属性设置set方法,然后在配置文件中注入。

    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> 
        <property name="name" value="test"></property>
        <property name="age" value="21"></property>
        <property name="birthday" ref="now"></property>
    </bean>
  • 涉及的标签:property

    • 属性:
      • name:找的是类中 set 方法后面的部分
      • ref:给属性赋值是其他 bean 类型的
      • value:给属性赋值是基本数据类型和 string 类型的
  • 优势:

    • 创建对象时没有明确的限制,可以直接使用默认构造函数
  • 弊端:

    • 如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

集合注入

  • 使用的方法还是构造方法注入与set方法注入的一种,只不过注入的对象是集合类型。

    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
        <!-- 给数组注入数据 --> 
        <property name="myStrs"> 
            <set>
                <value>AAA</value> 
                <value>BBB</value> 
                <value>CCC</value>
            </set>
        </property>
        <!-- 注入 list 集合数据 --> 
        <property name="myList"> 
            <array> 
                <value>AAA</value>
                <value>BBB</value> 
                <value>CCC</value>
            </array>
        </property>
        <!-- 注入 set 集合数据 --> 
        <property name="mySet"> 
            <list>
                <value>AAA</value> 
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>
        <!-- 注入 Map 数据 --> 
        <property name="myMap"> 
            <props> 
                <prop key="testA">aaa</prop> 
                <prop key="testB">bbb</prop>
            </props>
        </property>
        <!-- 注入 properties 数据 -->
        <property name="myProps">
            <map>
                <entry key="testA" value="aaa"></entry> 
                <entry key="testB"> <value>bbb</value>
                </entry>
            </map>
        </property>
    </bean>
  • 用于给List结构集合注入的标签:

    • list array set
  • 用于个Map结构集合注入的标签:

    • map props
  • 结构相同,标签可以互换*

请我喝杯咖啡吧~

支付宝
微信