struts2+hibernate+jQuery完成数据库课设

前言

身为一个软件工程的学渣,每每到了12周左右,就得经历一次连续熬夜的洗礼。平时上课又不认真听课,总是在玩手机,这不,现在好了,考试和课设全都挤在了一起,搞得人都傻了。
因为平时也没学什么技术,像那些学过前后端的同学,熟练的使用各种框架,这个课设一下子就做完了。而我这个什么都不会的人,只能一点点手撸代码,大部分都接近原生,会用struts2和hibernate还是因为作业要求才学的,哈哈哈,下面展示的时候可能使用不规范的话,还请见谅。写这篇文章算是对做完课设的一个总结吧,希望能帮到同是咸鱼的同学们。哈哈哈!

1、前端界面的架构设计

设计灵感
毕竟我是学Android方向的,Android总是要讲究优化的,同样是写界面代码,从一上手我就在想(我不会用框架0.0),有没有某种方式可以提高界面的利用率或者提高界面独立性。
于是找到了与Android APP的底部导航栏类似的东西,他是html中的标签iframe

这里解释一下,APP的底部导航栏其实就是Fragment和按钮的配合形成的,即每次点击按钮的时候切换Fragment。而我的关注点就是,用了Fragment之后,我可以实现把每一个界面当成一个独立的界面的去开发,要用的时候就才放进去,那html可不可以也实现同样的操作,让我独立的编写每一个完整的html,等要用的时候才把这个html放进去,然后不影响每一个html独立的js响应。答案当然是可以的。
这样做的好处是:

1.代码整体井然有序,在增加页面的时候不会影响其他页面的代码,依赖性小,该页面出现bug也不会影响其他的页面的运行。
2.每个页面都是按完整html去实现,调试和维护的时候很方便

整体设计
有了iframe这个家伙后,我就可以安心的开始码前端页面的代码了,于是我把整体的界面设计成这个样子。
在这里插入图片描述
为了保持界面较高的复用率,我将前端界面的导航栏(CommonFrame)和顶部栏(TopFrame)固定,内容主体部分通过切换嵌入,切换由导航栏控制。这样一来,这个东西就跟Android的底部导航栏很像了。

代码演示
类似Android的主活动,用了这种实现方式后,前端也有一个主html了

//省略头部
<body>
<iframe id="topframe" src="top.jsp" width="100%" height="50px" ></iframe>
<iframe id="leftframe" src="common.jsp" width="200px" height="100%"></iframe>
<iframe id="contentframe" src="home.jsp" onload="changeFrameWidth()" height="100%" ></iframe>
</body>

然后在导航栏CommonFrame中,我们就要触发js点击事件来切换ContentFrame中的内容。
这里注意一下,跟Android中的Fragment与Fragment的通信一样,一个Frame要控制另一个Frame的内容,一般都需要有中间者,而这里的中间者就是父布局,也就是index.html咯0.0
leftframe中触发下面的js代码就可以更改contentframe的页面

window.parent.document.getElementById(‘contentframe’).src = “xxx.jsp”

导航栏我是用ul li简单弄的,每次点击触发点击事件就行了
在这里插入图片描述
具体的前端页面可以参见下面的git图
在这里插入图片描述

2、后端分层的架构设计

这里相信大家学过框架之类的后会发现,框架已经给你封装得很好了,你在使用的时候已经就是按它原本设计好的分层方式去书写逻辑了,所以我才常常会感慨,你现在学的东西都是别人几年前都已经在用而且用得比你还好0.0,然后心生压力。

包结构
这里给大家看一下我的项目包结构
在这里插入图片描述
采用J2EE,即客户端页面为JSP,服务器端业务逻辑采用Java语言实现,实体类为JavaBean,Web服务器采用tomcat7.0,用struts2搭建,数据库使用hibernate映射。
在这里插入图片描述
表示层:采用Java Web开发技术。
控制层:采用Struts的Action组件。
业务层:封装业务逻辑(业务JavaBean)。
数据访问层:负责访问数据库,处理事务(数据访问JavaBean)。
数据库存储层:MySQL数据库。

层与层之间的调用关系
这里用一张图简单概括一下
在这里插入图片描述
代码演示
表示层的话,我们在前面已经介绍过了,这里就不再赘述。

控制层的话,每一个操作会对应一个action,我看了网上别人的项目,它对action的处理是在action中加了很多个ifelse判断,让一个action可以处理一个模块很多个操作。但是我感觉如果业务逻辑多了的话,这些action类最后会变得很臃肿,维护起来挺不方便的,每次增删改查都要往里面添加,所以我最后还是决定让一个action对应一个操作,所以我的action数量虽然多,但是代码里很少,名字起好也容易区别。
这里随便展示一个

public class GetGoalByTargetId extends ActionSupport {
    private CourseBuilderService service = new CourseBuilderService();

    @Override
    public String execute() throws Exception {
        ActionContext ac = ActionContext.getContext();
        NetUtils.sendEntitys(ac,service.getGoalByTargetID(NetUtils.getJsonStrings(ac)));
        return NONE;
    }
}

数据交互我后面会讲,因为很多重复代码,我就把重复代码放到utils包里面了,所以每一个action看起来就这么简洁。

业务层就是对应每一个service,一般在service里面会依赖DAO层的对象,一个DAO对象基本上会处理一个表的增删改查,如果某一个需求的业务太复杂的话,可以进行单表查询后,在业务层进行多表关联。

public class CourseBuilderService {
    TargetSupportDAO targetSupportDAO = new TargetSupportDAO();
    /**
     *  插入目标支撑度
     */
    public void insertGoalSupport(List<String> content){
        if (content != null){
            TargetSupportPO targetSupportPO = new TargetSupportPO();
            targetSupportPO.setGoal_id(Long.parseLong(content.get(0)));
            targetSupportPO.setTarget_id(Long.parseLong(content.get(1)));
            targetSupportPO.setSupport(Double.valueOf(content.get(2)));
            targetSupportDAO.addTargetPO(targetSupportPO);
        }
    }
}

数据访问层对应DAO包下的内容,这里要求每一个DAO类对应每一个表的增删改查的操作,因为项目不是很复杂,所以我没有对DAO进行抽象成接口,正常开发好像是要有这个操作,你们注意下就行。虽然用了hibernate框架,但是可能我才疏学浅,没能发现它的好用之处0.0(在做课设的时候,这个家伙把我搞得挺难受的,遇到各种莫名其妙的bug,哎不提了),所以我还是喜欢用原生sql去查询,多表查询调试完一串sql放进去就出结果,哈哈哈,这感觉是特别爽。当然简单的单表查询我还是用hql的,毕竟可以省去类转换的操作。(注意原生sql的查询得到的类是object对象数组,这个bug搞了我很久,让我学会了调试技能0.0,f8都快给我按烂了)
这里展示的是hibernate中原生sql写法,出现斜杆也没关系,使劲撮,可以用的

query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
是数据封装成map方便根据列名获取数据

    /**
     * 根据课程名、目标名和版本号查找个人达成度
     * content.get(0) ===> 课程名
     * content.get(1) ===> 目标名
     * content.get(2) ===> 版本号
     * @return {ps(个人达成度)}
     * @throws HibernateException
     */
    public List findPersonalAchievement(List<String> content,String no) throws HibernateException{
        Session session = hsp.getSession();
        Transaction tx   = session.beginTransaction();
        SQLQuery query = session.createSQLQuery("SELECT SUM(course_assess.Weight * ds.personSc) as ps FROM course_assess,(\n" +
                "SELECT dt.Course_Assess_ID,grade.StuNo,SUM(grade.Score)*(CASE \n" +
                "\tWHEN Weight > 1 THEN\n" +
                "\t\t1\n" +
                "\tELSE\n" +
                "\t\tWeight\n" +
                "END\n" +
                ") as personSc FROM grade,(\n" +
                "SELECT * FROM details WHERE details.Goal_ID = (\n" +
                "\tSELECT goal.ID FROM goal WHERE goal.Course_ID = (\n" +
                "\tSELECT course.ID from course,version \tWHERE course.Name = '"+content.get(0)+"' AND course.Version_ID = version.ID  AND version.Year = '"+content.get(2)+"'\n" +
                "\t) AND goal.num = '"+content.get(1)+"'\n" +
                ") \n" +
                ") as dt WHERE dt.ID = grade.Detail_ID  and grade.StuNo = '"+no+"' GROUP BY dt.Course_Assess_ID\n" +
                ") as ds WHERE ds.Course_Assess_ID = course_assess.ID GROUP BY ds.StuNo");
        query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
        List list = query.list();
        tx.commit();
        session.close();
        return list;
    }

数据库存储层的话就不用说了吧,用啥数据库,就在hibernate.cfg.xml配置文件中改一下就好了,上课会讲的,注意听0.0

3、前后端的数据交互

数据交互了,经过debug的跌打滚打,发现了request和respond类中的一个属性是用来存值的(debug调试是真的香-。-),于是,数据交互就使用了流的形式去交互。(实不相瞒,在我发现这个欣喜之余,我同学走过来看了下,告诉我说是他们学习后台视频就有的,我裂开了0.0哈哈哈,我太菜了)
主要是形式是前端使用ajax,传输数据封装成Json格式,然后在后台action中再把数据获取到,解析成实体类去使用
在这里插入图片描述
代码实现
js代码
看看js代码,原生写太冗余了,所以用了JQuery来写ajax
这个固定写法挺好了,每次只要改了data的内容还有url地址,就可以传递不同的地方了,success中的函数返回的时候后台传来的响应内容,通过查询得到的数据一般可以在这里处理。
如果你们有心的话后,可以再对他进行封装成一个方法,写成观察者模式也行。

//获取表单数据
function getData() {
    var data = {
        courName:  $("#courName").val(),
        selectGoal: $("#selectGoal").children('option:selected').text(),
        selectVersion: $("#selectVersion").children('option:selected').text()
    }
    return data;
}
function getInfo() {
    //    根据三种输入情况更新表格
    var data = getData();
    $.ajax({
        url: "getOverallAchievement.action",//获取总体达成数据
        type: "POST",
        data: data,
        dataType: "json",
        contentType: "application/x-www-form-urlencoded",
        success: function (msg) {***省略***}})
}

java代码
后台java代码的处理会分两个步骤,一个是接受json数据解析,一个是封装成json数据发送,这里把代码放这里大家可以参考下。解析的数据我用一个集合去存放了,对了上面那个data的值,按顺序存而已。

//这个是action中的代码
    @Override
    public String execute() throws Exception {
        ActionContext ac = ActionContext.getContext();
        List<String> jsonStrings = NetUtils.getJsonStrings(ac);
        NetUtils.sendEntitys(ac,service.getPersonalAchievementInfo(jsonStrings));
        return NONE;
    }

//用到两个方法在下面,我是放到utils中的
   public static List<String> getJsonStrings(ActionContext ac) {
        HttpServletRequest request = (HttpServletRequest)ac.get(StrutsStatics.HTTP_REQUEST);
        Map<String,String[]> jsondata = request.getParameterMap();
        Set<String> strings = jsondata.keySet();
        List<String> content = new ArrayList<>();
         for (String str:strings
        ) {
            content.add(jsondata.get(str)[0]);
        }
        return content;
    }

    public static  <T> void sendEntitys(ActionContext ac,T entity) throws Exception {
        HttpServletResponse response = (HttpServletResponse) ac.get(ServletActionContext.HTTP_RESPONSE);
        response.setContentType("text/html;charset=utf-8");
        Gson gson = new Gson();
        response.getWriter().write(gson.toJson(entity));
    }

4、遇到其他的问题

4.1 URL有中文要怎么保留

前端js使用二次编码encodeURI(encodeURI(url));
后台接收的时候使用一次译码URLDecoder.decode(“chinese string”,“UTF-8”)

这样如果要get请求添加参数的话,就不会出现中文乱码了

4.2 Action不一定非要return转发一个页面,可以return null

    @Override
    public String execute() throws Exception {
       return NONE;
    }

struts.xml的action标签就不用添加result了
    <action name="testAction" class="com.XiaoTou.action.testAction"></action> 

4.3 缩放网页导致ContentFrame内容变形
解决方法

<iframe id="contentframe" src="home.jsp" onload="changeFrameWidth()" height="100%" ></iframe>
//改变
function changeFrameWidth(){
    var ifm= document.getElementById("contentframe");
    ifm.width= document.body.clientWidth -205 //这个205可以调试改变
}
window.onresize=function(){
    changeFrameWidth();
}

4.4 action跳转的时候找不到静态css等的资源

在struts2配置文件中package标签加入 namespace="\"

<package name="PCMS" extends="struts-default" namespace="/">

4.5 hibernate进行更新的时候不能漏了executeUpdate()
不然会出现不报错但是没结果0.0,搞死你哟

session.createSQLQuery(mySql).executeUpdate();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值