前言
这一切都关于我们JAVA老师布置的一个商城系统大作业,因为年糕君主攻前端方面啦,所以在JAVA框架上绝对是一个萌新,不过秉着老师说的学会一个框架只要半天的说法,最后大概一个礼拜的时间,还是马马虎虎达到了这样那样的功能。
这其中出了很多BUG(而且做的进度曾让我感觉很崩溃😭)~好不容易结课了,所以来好好总结一下。
【P.S】当然我这应该有一些不合理的设计和开发方法(严肃)!希望各位看官能温柔一点,有错误或更好意见欢迎告诉我。
技术和工具
前端相关:Vue.js、Vue-cli、webpack
后端相关:struts2.0、Spring 3.1、Hibernate 3、JUnit 4、MyEclipese
数据库相关:MySQL 5.5
实现的需求
页面需求:
页面我是在网易云商城的基础上进行了修改(因为我热爱音乐呀),写了一个首页、商品详细页面、购物车页、我的订单页和登录注册页。
功能需求:
- 登录、注册(判断输入合法)
- 首页显示、分类显示、搜索
- 购物车、订单显示
前端相关
情况1:使用Vue-cli搭建了多页面的应用
我这个小项目虽然使用了Vue来做,但是还是想做成多页面的。因为我感觉这几个页面之间可复用的组件很少,重新空一个页面出来写也没关系。
因为也看过一些类似的文章来讲解如何配置,所以这里修改一下Vue-cli的配置就容易达成目的。不过也感觉到这样在每次启动webpack进行第一次打包的时候会很慢。
情况2:未使用vue-router进行跳转
因为是多页面所以直接跳转就可以了,但是在某些页面内可以局部根据URL的改变来改变内容。这里用了vue-router的原理来进行检测,根据URL的哈希改变和监听就可以完成预期的想法(噗后来回想起来用?来GET方法不也差不多啊...不过这样就会有明显的页面跳转)。
window.location常用的属性:
hash 从井号 (#) 开始的 URL(锚)
host 主机名和当前 URL 的端口号
hostname 当前URL的主机名
href 完整的URL
pathname 当前URL的路径部分
port 当前URL的端口号
protocol 当前 URL 的协议
search 从问号 (?) 开始的 URL
情况3:关于vuex的使用
因为是多页面,所以vuex可以说是没啥作用QAQ,因为每一个页面都是自己有一个根store,所以它们之间的数据变化是交互不了的,于是最后这个小项目没有使用vuex。
情况4:跨域的问题
虽然使用了axios,但是跨域的问题还是会有的,并且后面发现很棘手的就是cookie都是不携带的,小项目使用了后台进行CORS设置来帮助它跨域。
axios.defaults.withCredentials = true
情况5:无关系的组件间通信
在根部加入一个Vue实例,通过它来进行一个事件传播的中转,也就是所谓的EventBus,同样的网上也有很多类似的文章。(不一定是$root,也可能是$root.$root,要见具体情况而言)
详解Vue 非父子组件通信方法(非Vuex)
情况6:localStorage
localStorage只能存字符串,所以要用JSON.parse
和JSON.stringify
进行相互转换然后操作。
情况7:Vue和style
这个我总是没记清楚,直接嵌入绑定的时候,有[...]
,也有{...}
。
数组的形式
:class="[classA, classB]"
:class="['tip', usernameTip.length <= 0 ? 'hidden ': '']
:class="[classA, { classB: isB, classC: isC }]
对象的形式
:class="{ 'class-a': isA, 'class-b': isB }
情况8:给数组包含的对象的属性赋值,Vue不会检测到更新
使用在内部就是使用this.$set(数组成员[索引], '属性名', 值)
可以实现。
情况9:多个异步
也就是想发送多个异步请求,最后整合它们的结果。但是往往是直接执行后面的同步代码了,所以会出现渲染的时候拿到的东西是空。因为时间不够,我用了以前的做法,就是递归调用来解决。
情况10:this的指向
在调用别的组件后,在它的内部这个this很可能就会被修改了,这个时候箭头函数的好处就来了,不需要再定义一个临时变量来存着vue的this。
情况11:对于前端安全的理解
做的时候,我就想着,对象数据之类的在控制台都似乎可以很容易的改变,这样可以绕过去发送请求。但是在以前也是这样的啊,所以说前端本来就是不安全的,所以在后台也一定要做相应的处理措施。而之所以前台也要做一些验证控制,也同样是可以方便正常用户的体验和使用,不用等待后台发回消息的时间这样。
情况12:font-awesome的使用
打包出来的时候,会显示不了图标,还要自己在页面引入一个链接。
后端相关
下面以一个萌新的视角来阐述关于SSH的种种:
- struts:它的action相当于是servlet的作用,也就是我们访问后台配置的URL(默认是.action)都是它提供的。
- Spring:一般情况下,我们都是调用某个类的某个方法,这样总要创建一个对象来调用,有了它去注入接口,就可以直接调用
接口.方法
来完成任务。 - Hibernate:简化也更安全化了对数据库的操作。
结构
- mysho下放了Hibernate默认创建的类
HibernateSessionFactory
; - mysho.action放了所有的Action类,包括UserAction、CartAction和ShowAction,它们会有一个service的成员来调用对应的方法;
- mysho.service放的是service类,这里直接调用Dao类进行相应的操作。
- mysho.dao放的是所有和数据库进行操作的Dao类;
- mysho.model放的是所有类原型,包括User、Item(商品)、Order(订单)和Type;
- mysho.utils是工具类,辅助操作。
框架的整合
建议使用IDE自己的配置~这样方便统一换包啥的。如果出现配置文件和框架jar包都没啥错误的情况下还是出现了问题,而且怎么百度都搜不到,请考虑以下方法:
- 更换JDK的版本
- 更换某个框架的版本
- 如果不管怎么改还是出现了同样的错误,请点击Project -> clean,清除缓存。如果没用,就打开Tomcat的文件夹看看里面部署的内容修改了吗,如果一直不改,就换一个workspace吧。
配置Hibernate
这里我没有用逆向工程,Spring的注入方式也是setter注入。
除了默认给配置的,还需要写hbm.xml文件的映射:
<mapping resource="com/mysho/model/User.hbm.xml" />
如果在项目中使用了openSession,还需要配置:
<property name="hibernate.current_session_context_class">thread</property>
配置以UTF-8编码进行连接,防止中文乱码:
<property name="connection.characterEncoding">utf-8</property>
配置Spring
因为使用的是setter注入,所以在这里必须要写清楚所有要注入的数据的内容。比如:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml">
</property>
</bean>
<bean id="userDao" class="com.mysho.dao.UserDaoImp">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
这里配置了两个bean,一个叫做sessionFactory,一个叫做userDao,userDao里面配置了一个sessionFactory的属性,它指向(ref)id是sessionFactory的东西,所以这样运行的时候Spring就知道应该注入什么。
配置Struts
这里有一个巨大的坑!而且之前百度了好久都没有搜索到正确的答案。
如果配置好项目,但是发现所有的接口成员都是null,那么请考虑是不是这个问题:
<action name="showIndexItem" class="showAction" method="showIndexItem"/>
配置action的时候,它所指向的class,请写Spring中id对应的那个action的class,不能写成包.class,因为这样,Struts就不会经过Spring的注入,因为你更本没把它们两个联系起来。
另外还有配置编码:
<constant name="struts.i18n.encoding" value="utf8" />
配置web.xml
<!-- ***Spring 容器初始化*** -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.util.IntrospectorCleanupListener
</listener-class>
</listener>
<!-- 配置编码 -->
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ******Struts2核心过滤器***** -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意啦,这里的org.apache.struts2.dispatcher.FilterDispatcher
是因为我的strut是2.0版本的,版本很低,高版本的写法不是这样的。
其他
情况1:配置跨域
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Origin", 你的URL);
response.setHeader("Access-Control-Allow-Methods", 你的方法);
这里如果Access-Control-Allow-Credentials
为true的话,Access-Control-Allow-Origin
不允许设置为*
,必须精确填一个地址。
情况2:以JSON形式返回
response.setHeader("Content-Type", "application/json");
因为使用了前后端分离,所以必然要返回JSON了~这样虽然struts有一个JSON插件包,但是由于我的版本一直匹配不上,我就找到了一种最原始的方法来实现,但是实际上并不建议这样做。另一方面action进行配置:
<package name="default" namespace="/" extends="struts-default">
<action name="checkname" class="userAction" method="checkUsername"/>
</package>
向checkname.action发送请求即可,虽然控制台会出现一个警告说未设置成功/失败的跳转页面,但是实际上不影响使用。
情况3:报错难以排除问题根源
那么请使用JUnit来编写测试用例吧!
这个方法真的超级好使,不过在测试Spring的时候,需要手动从配置文件中去提取出容器来,或者使用注入的方式来实现提取容器,百度都有很多文章。
情况4:关于setter注入
每个要被注入的接口成员需要有对应的setter方法,另外所在的类也需要一个没有参数的构造函数。
情况5:关于hql语句
注意:=这个符号,它的前后不要留空格:
from com.mysho.model.User user where user.username=:usernam
设置开始寻找的位置,以及获取的条数:
query.setFirstResult(start);
query.setMaxResults(size);
如果未求使用事务,控制台报错,改成事务的形式就行了:
Session s = sessionFactory.getCurrentSession();
Transaction transaction = s.beginTransaction();
...
transaction.commit();
情况6:session获取不一致
就是在这里设置了session的值,但在另一个地方却拿到的是空,
这个时候就要考虑应该是因为它们根本就不在一个容器内,
因为发送请求的时候必须要带上相应的cookie才能识别~
但也有办法让所有容器共享数据,使用:
ServletActionContext.getServletContext().getAttribute(...)
ServletActionContext.getServletContext().setAttribute(..., ...)
情况7:JSON转换的问题
JSONArray.fromObject(...):把一个list转换为JSON。
JSONObject.fromObject(...):把一个Object转换为JSON。
另外对象中存在Date类型的JSON会报异常,需要另外做更多特殊处理才行,并且使用java.sql.Date和java.util.Date来操作的话又会有不同结果。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。