4

前言

这一切都关于我们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.parseJSON.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来操作的话又会有不同结果。


MOCHIKO
318 声望29 粉丝