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

税友实习日记第六周小结

本周工作内容

  1. 本周主要进行的工作是对与开发模块的bug修改,不得不说,整个流程下来,最让我头疼觉得烦的就是现在的这个测试阶段了,改bug真是个麻烦的事情,尤其是对于前端样式的修改,对于我这种后台开发人员来说,真是麻烦啊。

  2. 本周还在进行一个通道的开发,是全新学习的一个内容,我的理解是数据库的数据交互,将一个数据库中的数据同步到另一个数据库,但是有一个细节上的问题感觉很麻烦,大体上一条业务只需要执行一次同步就可以了,但是这个业务中有一个细节需要封装成一个集合进行多次同步,很麻烦。

  3. 对于改bug的体验就是,一生二,二生三,三生万物,改完一个bug,衍生出其他的bug,好烦啊。

本周开发中的一些小问题

  1. 对于开发中的需求理解及自测需要更加注重,不然到了测试阶段真是麻烦啊。

  2. 学习新东西的过程很痛苦,但是学完以后会很有成就感,不要排斥,慢慢接受,这样才会有成长。

总结

对于开发过程中忽视的东西在测试过程中有了更清晰的认识,争取同一个错误下次不要再犯,还是要细心!细心!细心啊!!!。


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

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

税友实习日记第七周小结

本周工作内容

  1. 本周的工作内容是对于通道的学习与使用,对于通道的理解是分为发送端与接收端,发送端用于传入参数然后查询出符合条件的需要进行传输的数据库记录,而接受端则执行对于的方法进行数据库的读写,其中发送端与接收端的连接是一个自己定义的PO实体对象。

  2. bug的修改已经基本完成,剩下通道方面的东西。

本周开发中的一些小问题

  1. 对于通道,似乎是公司自己封装的一个东西,使用起来极为不方便的地方是只能在测试环境进行测试是否正确,因为这涉及到两个独立的数据库之间的数据传输,而开发环境没有这个条件,还有就是通道无法debug,只能自己拉日志进行排查,有些错误实在不知道哪错了,有点难受。

总结

通道的东西已经了解了大概八十的样子,已经会使用了,只是还有一些坑,以及进行错误排查及修改的方法需要多加练习,其中本周碰到的一个坑是PO实体对象中的数据类型必须和数据库中一一对应,比如数据库中为NUMBER,DATE等数据类型无法用String来接收。

本周还进行了为期两天半的培训,我本人是有点社恐的,一开始还有点难受,但是随着时间久了,竟然觉得这么一个小team的感觉还挺好,很有爱,还进行了各种团体活动,反正挺温暖的,最后还进行了情景剧的表演,表演完以后培训也就结束了,大家也就就此别过了,有点不舍。


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

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

税友实习日记第五周小结

本周工作内容

  1. 新模块的开发以及处于完成阶段,剩下一个页面的功能需要等待前端完成进行继续开发,其页面的后台功能已基本完成。

  2. 有一个页面中的排序功能,是同时排序,主关键字段相同时,则用第二关键字段进行排序,实现此功能可以使用order by多个条件,但是要注意的是排序的时候要对空值进行处理,否则空值会默认排在第一个。

  3. 对于开发中粗心的地方有了更多注意,比如后台返回数据是集合还是一个对象,如果前端调用的方法是对于集合的,即使这个功能只会返回一条记录,也该返回一个集合。

  4. 对于后台提取到的数据是HTML类型的,要在前台页面显示部分,可以只提取其中的纯文本内容,用String发replaceAll加正则过滤html标签及特殊字符,然后再对中英文的长度进行处理,因为中英文的字节数不同。

本周开发中的一些小问题

  1. 后台该返回的数据类型,应该和前台调用的方法匹配。

  2. 对于开发过程中出现的问题,未必是逻辑上或者代码上有错误,可能是项目的配置中与使用的东西不匹配,此时需要往项目的配置中钻,找到对应的地方进行匹配解决。

总结

开发能力已经处于上手水平,对于基本的开发内容已经可以顺风顺水的完成,找错误的能力也有所提高,对于SQL的理解也有了更深的理解,可以比较灵活的运用,对于问题的解决思路也更加有思路了。


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

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

税友实习日记第四周小结

本周工作内容

  1. 对于负责的任务管理模块进行了细节上的优化,下周进行代码评审与测试,希望没啥大问题。

  2. 有一个新负责的模块,是没有接触过的几乎全新的内容,是一个论坛性质的模块。

  3. 对于一些问题的解决有了更灵活的思路,比如查数据库数据时,有时可以不用创建两个方法,只要在SQL中操作就行,比如JS中两个方法要先后执行,可以不这么做,转到后台去完成。

本周开发中的一些小问题

  1. 前台页面显示的问题,datagrid中有一个输入框,此时想要使它有默认值,只能在后台操作,因为他的数据是写上去的,直接设置默认值是无效的。

总结

对于开发中,开发速度有了很大提高,只是方法中老有问题,要是开发过程一路顺利,那么很快就能完成,但是我喜欢钻牛角尖,一旦遇到一个小问题就会花很长时间去解决它,甚至有时候还是白费时间,而这个问题又是个小问题,因此会耽误很长时间,以后开发时需要改掉这个毛病,实在一时解决不了的小问题就先放掉,先做大头。


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

税友实习日记:一周小结(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:用于指定存入的数据类型。

请我喝杯咖啡吧~

支付宝
微信