决策支持系统 系统分析设计实现

一、需求分析: 

1、 用户注册、登陆功能。

2、 问题描述页面。

3、 两变量决策:准确输入两个变量后,系统给出最优结果和分析过程。

4、 一变量决策:输入一个变量,和另一个变量的范围,系统给出另一个变量在变化过程中的最优结果和折线图。

5、 零变量决策:系统给出在“购买率”分别为3%、4%、5%、6%、7%时,另一个变量在变化过程中的折线图。

6、 每次得出决策结果后,用户可以选择保存结果。在“我的决策记录”中,用户可以查看过去保存的决策记录。

 

二、整体设计

1、 结构:B/S

2、 技术:

Java EE的spring、struts、hibernate框架;

用jfreechart画折线图;

jquery框架;

Css、html、freemarker;

3、 开发工具:

Eclipse、photoshop、firebug

4、 程序规模:(4天*1人)

*.java:1840行

*.js:421行

*.css:1529行

*.ftl:501行

 

三、详细设计和实现  

1、 系统逻辑结构设计:

整个项目采用MVC模式,分层设计提高了系统的易维护性、可扩展性,减少代码的耦合程度。

2011060419162487.png

2、 模块详细设计实现:

(其他略。。。。)

生产折线图的功能:

(1)、客户端ajax提交请求:

 
  
1 $( ' #result ' )
2 .click(
3 function () {
4 disableSaveButton();
5 var paramName = $.trim($(
6 ' #main_box ul li.paramSelected input.radio ' )
7 .val());
8 var paramValue = $.trim($(
9 ' #main_box ul li.paramSelected input.input ' )
10 .val());
11 var purchaseRate = $.trim($( ' #purchaseRate ' ).val());
12 var precisionType = $
13 .trim($(
14 ' #main_box ul li.precisionSelected input.radio ' )
15 .val());
16 var minPrecision = $.trim($( ' #minPrecision ' ).val());
17 var maxPrecision = $.trim($( ' #maxPrecision ' ).val());
18 var intervalPrecision = $.trim($( ' #intervalPrecision ' )
19 .val());
20
21 var decisionUrl = ' one.action?paramName= ' + paramName
22 + ' &paramValue= '
23 + encodeURIComponent(paramValue)
24 + ' &precisionType= ' + precisionType
25 + ' &minPrecision= '
26 + encodeURIComponent(minPrecision)
27 + ' &maxPrecision= '
28 + encodeURIComponent(maxPrecision)
29 + ' &intervalPrecision= '
30 + encodeURIComponent(intervalPrecision);
31
32 waitLoading();
33 $
34 .ajax({
35 type : ' post ' ,
36 url : ' one.action ' ,
37 data : ' paramName= '
38 + paramName
39 + ' &paramValue= '
40 + encodeURIComponent(paramValue)
41 + ' &precisionType= '
42 + precisionType
43 + ' &minPrecision= '
44 + encodeURIComponent(minPrecision)
45 + ' &maxPrecision= '
46 + encodeURIComponent(maxPrecision)
47 + ' &intervalPrecision= '
48 + encodeURIComponent(intervalPrecision),
49 error : function () {
50 errorLoading();
51 alert( ' 数据处理失败,请重试! ' );
52 },
53 success : function (msg) {
54 var json = eval( ' ( ' + msg + ' ) ' );
55 var success = json[ ' success ' ];
56 var hitsError = json[ ' hitsError ' ];
57 var purchaseRateError = json[ ' purchaseRateError ' ];
58 var scopeError = json[ ' scopeError ' ];
59 var intervalError = json[ ' intervalError ' ];
60 var graph = decodeURIComponent(json[ ' graph ' ]);
61 var result = json[ ' result ' ];
62
63 $(
64 ' #main_box ul li.hits div.errorMessage ' )
65 .html( '' );
66 $(
67 ' #main_box ul li.purchaseRate div.errorMessage ' )
68 .html( '' );
69 $(
70 ' #main_box ul li.precision ul li div.errorMessage ' )
71 .html( '' );
72
73 if (success) {
74 clearLoading();
75 $( ' #resultString img ' ).attr( ' src ' ,
76 decodeURIComponent(graph));
77 $( ' #analysisString .content ' ).html(
78 result);
79 enableSaveButton();
80 $( ' #saveResult ' ).siblings( ' input.url ' ).val(decisionUrl);
81 $( ' #saveResult ' ).siblings( ' input.hits ' ).val(paramValue);
82 $( ' #saveResult ' ).siblings( ' input.purchaseRate ' ).val(paramValue / 100);
83 $( ' #saveResult ' ).siblings( ' input.paramName ' ).val(paramName);
84 } else {
85 errorLoading();
86 if ( ' undefined ' != ( typeof hitsError)
87 && null != hitsError
88 && '' != hitsError) {
89 $(
90 ' #main_box ul li.hits div.errorMessage ' )
91 .html(hitsError);
92 }
93 if ( ' undefined ' != ( typeof purchaseRateError)
94 && null != purchaseRateError
95 && '' != purchaseRateError) {
96 $(
97 ' #main_box ul li.purchaseRate div.errorMessage ' )
98 .html(purchaseRateError);
99 }
100 if ( ' undefined ' != ( typeof scopeError)
101 && null != scopeError
102 && '' != scopeError) {
103 $(
104 ' #main_box ul li.precision ul li.scope div.errorMessage ' )
105 .html(scopeError);
106 }
107 if ( ' undefined ' != ( typeof intervalError)
108 && null != intervalError
109 && '' != intervalError) {
110 $(
111 ' #main_box ul li.precision ul li.interval div.errorMessage ' )
112 .html(intervalError);
113 }
114 }
115 }
116
117 });
118 });

(2)、OneAction类响应ajax请求:(进行数据校验,返回系统生成的决策字符串和折线图的url(例如,chartHits.action?hits=555555555555&min=0.03&max=0.07&interval=0.01))

 
  
1 private void initJson() throws JSONException {
2 json = new JSONObject().put( " success " , success)
3 .put( " hitsError " , hitsError)
4 .put( " purchaseRateError " , purchaseRateError)
5 .put( " scopeError " , scopeError)
6 .put( " intervalError " , intervalError).put( " graph " , graph).put( " result " , result)
7 .toString();
8 }
9
10 public String execute() throws DssException {
11 if ( null == paramName
12 || ( ! paramName.equals( " hits " ) && ! paramName
13 .equals( " purchaseRate " ))) {
14 throw new DssException( " *请至少选择一个参数! " );
15 }
16
17 if ( null == precisionType
18 || ( ! precisionType.equals( " default " ) && ! precisionType
19 .equals( " advanced " ))) {
20 throw new DssException( " *请至少选择一个折线图精确度类型! " );
21 }
22 try {
23 if (paramName.equals( " hits " )) {
24 Long numH;
25
26 Double numMin;
27 Double numMax;
28 Double numInterval;
29
30 if ( null == paramValue || paramValue.equals( "" )) {
31 success = false ;
32 hitsError = " *字段不能为空! " ;
33 initJson();
34 return SUCCESS;
35 }
36
37 String h = URLDecoder.decode(paramValue, " UTF-8 " );
38 if ( ! h.matches( " \\d+ " )) {
39 success = false ;
40 hitsError = " *字段只能为正整数! " ;
41 initJson();
42 return SUCCESS;
43 }
44
45 try {
46 numH = Long.parseLong(h);
47 } catch (NumberFormatException e) {
48 success = false ;
49 hitsError = " *字段只能为正整数! " ;
50 initJson();
51 return SUCCESS;
52 }
53 if (numH < 0 ) {
54 success = false ;
55 hitsError = " *字段只能为正整数! " ;
56 initJson();
57 return SUCCESS;
58 }
59
60 /*
61 * precision validate
62 */
63 if (precisionType.equals( " advanced " )) {
64 if ( null == minPrecision || minPrecision.equals( "" )
65 || null == maxPrecision || maxPrecision.equals( "" )) {
66 success = false ;
67 scopeError = " *字段不能为空! " ;
68 initJson();
69 return SUCCESS;
70 }
71 if ( null == intervalPrecision
72 || intervalPrecision.equals( "" )) {
73 success = false ;
74 intervalError = " *字段不能为空! " ;
75 initJson();
76 return SUCCESS;
77 }
78 String min = URLDecoder.decode(minPrecision, " UTF-8 " );
79 String max = URLDecoder.decode(maxPrecision, " UTF-8 " );
80 String interval = URLDecoder.decode(intervalPrecision,
81 " UTF-8 " );
82 if ( ! min.matches( " [\\.\\d]*[\\d]+[\\.\\d]* " )
83 || ! max.matches( " [\\.\\d]*[\\d]+[\\.\\d]* " )) {
84 success = false ;
85 scopeError = " *字段只能为数字! " ;
86 initJson();
87 return SUCCESS;
88 }
89 if ( ! interval.matches( " [\\.\\d]*[\\d]+[\\.\\d]* " )) {
90 success = false ;
91 intervalError = " *字段只能为数字! " ;
92 initJson();
93 return SUCCESS;
94 }
95
96 try {
97 numMin = Double.parseDouble(min) / 100 ;
98 numMax = Double.parseDouble(max) / 100 ;
99 } catch (NumberFormatException e) {
100 success = false ;
101 scopeError = " *字段只能为数字! " ;
102 initJson();
103 return SUCCESS;
104 }
105 try {
106 numInterval = Double.parseDouble(interval) / 100 ;
107 } catch (NumberFormatException e) {
108 success = false ;
109 intervalError = " *字段只能为数字! " ;
110 initJson();
111 return SUCCESS;
112 }
113 if (numMin < 0 || numMax < 0 || numMin >= numMax) {
114 success = false ;
115 scopeError = " *字段只能为正数,并且最大值要大于最小值! " ;
116 initJson();
117 return SUCCESS;
118 }
119 if (numInterval < 0 ) {
120 success = false ;
121 intervalError = " *字段只能为正数! " ;
122 initJson();
123 return SUCCESS;
124 }
125
126 } else { // default
127 numMin = 0.03 ;
128 numMax = 0.07 ;
129 numInterval = 0.01 ;
130 }
131
132 // // /
133
134 /*
135 * get graph 点击数:(Long) numH 购买率:(Double) numMin numMax
136 * numInterval
137 */
138 success = true ;
139 graph = URLEncoder.encode( " chartHits.action?hits= " + numH
140 + " &min= " + numMin + " &max= " + numMax + " &interval= "
141 + numInterval, " UTF-8 " );
142 result = Util.bestSolutions(numH);
143 initJson();
144 return SUCCESS;
145
146 } else {
147 Double numR;
148
149 Long numMax;
150 Long numMin;
151 Long numInterval;
152
153 if ( null == paramValue || paramValue.equals( "" )) {
154 success = false ;
155 purchaseRateError = " *字段不能为空! " ;
156 initJson();
157 return SUCCESS;
158 }
159 String r = URLDecoder.decode(paramValue, " UTF-8 " );
160 if ( ! r.matches( " [\\.\\d]*[\\d]+[\\.\\d]* " )) {
161 success = false ;
162 purchaseRateError = " *字段只能为数字! " ;
163 initJson();
164 return SUCCESS;
165 }
166
167 try {
168 numR = Double.parseDouble(r) / 100 ;
169 } catch (NumberFormatException e) {
170 success = false ;
171 purchaseRateError = " *字段只能为数字! " ;
172 initJson();
173 return SUCCESS;
174 }
175 if (numR < 0 ) {
176 success = false ;
177 purchaseRateError = " *字段只能为正数! " ;
178 initJson();
179 return SUCCESS;
180 }
181
182 /*
183 * precision validate
184 */
185 if (precisionType.equals( " advanced " )) {
186 if ( null == minPrecision || minPrecision.equals( "" )
187 || null == maxPrecision || maxPrecision.equals( "" )) {
188 success = false ;
189 scopeError = " *字段不能为空! " ;
190 initJson();
191 return SUCCESS;
192 }
193 if ( null == intervalPrecision
194 || intervalPrecision.equals( "" )) {
195 success = false ;
196 intervalError = " *字段不能为空! " ;
197 initJson();
198 return SUCCESS;
199 }
200
201 String min = URLDecoder.decode(minPrecision, " UTF-8 " );
202 String max = URLDecoder.decode(maxPrecision, " UTF-8 " );
203 String interval = URLDecoder.decode(intervalPrecision,
204 " UTF-8 " );
205 if ( ! min.matches( " \\d+ " ) || ! max.matches( " \\d+ " )) {
206 success = false ;
207 scopeError = " *字段只能为正整数! " ;
208 initJson();
209 return SUCCESS;
210 }
211 if ( ! interval.matches( " \\d+ " )) {
212 success = false ;
213 intervalError = " *字段只能为正整数! " ;
214 initJson();
215 return SUCCESS;
216 }
217
218 try {
219 numMax = Long.parseLong(max);
220 numMin = Long.parseLong(min);
221 } catch (NumberFormatException e) {
222 success = false ;
223 scopeError = " *字段只能为正整数! " ;
224 initJson();
225 return SUCCESS;
226 }
227 try {
228 numInterval = Long.parseLong(interval);
229 } catch (NumberFormatException e) {
230 success = false ;
231 intervalError = " *字段只能为正整数! " ;
232 initJson();
233 return SUCCESS;
234 }
235 if (numMax < 0 || numMin < 0 || numMax <= numMin) {
236 success = false ;
237 scopeError = " *字段只能为正整数,且最大值大于最小值! " ;
238 initJson();
239 return SUCCESS;
240 }
241 if (numInterval < 0 ) {
242 success = false ;
243 intervalError = " *字段只能为正整数! " ;
244 initJson();
245 return SUCCESS;
246 }
247 } else { // default
248 numMin = 450000l ;
249 numMax = 800000l ;
250 numInterval = 20000l ;
251 }
252
253 /*
254 * get graph 购买率:(Double) numR 点击数:(Long) numMin numMax
255 * numInterval
256 */
257 success = true ;
258 graph = URLEncoder.encode(
259 " chartPurchaseRate.action?purchaseRate= "
260 + URLEncoder.encode(numR.toString(), " UTF-8 " )
261 + " &min= " + numMin + " &max= " + numMax
262 + " &interval= " + numInterval, " UTF-8 " );
263 result = Util.bestSolutions(numR);
264 initJson();
265 return SUCCESS;
266
267 }
268 } catch (UnsupportedEncodingException e) {
269 e.printStackTrace();
270 throw new DssException( " 解码过程出错~ " );
271 } catch (JSONException e) {
272 e.printStackTrace();
273 throw new DssException( " 生成json字符串过程出错~ " );
274 }
275
276 // return SUCCESS;
277 }

(3)ChartHitsAction类负责产生折线图:

 
  
1 public String execute() {
2 chart = jFreeChartService.createChartHits(hits, min, max, interval);
3 return SUCCESS;
4 }

配置文件:

 
  
1 < action name ="chartHits" class ="com.dss.action.chart.ChartHitsAction" >
2 < result name ="success" type ="chart" >
3 < param name ="width" > 960 </ param >
4 < param name ="height" > 640 </ param >
5 </ result >
6 </ action >

(4)JFreeChartServiceImpl类:

 

 
  
1 package com.dss.service.impl;
2
3 import java.awt.Color;
4 import java.awt.Font;
5
6 import org.jfree.chart.ChartFactory;
7 import org.jfree.chart.JFreeChart;
8 import org.jfree.chart.plot.CategoryPlot;
9 import org.jfree.chart.plot.PlotOrientation;
10 import org.jfree.chart.renderer.category.LineAndShapeRenderer;
11 import org.jfree.chart.title.TextTitle;
12 import org.jfree.data.category.DefaultCategoryDataset;
13
14 import com.dss.service.JFreeChartService;
15 import com.dss.service.Util;
16
17 public class JFreeChartServiceImpl implements JFreeChartService {
18 public JFreeChart createChartHits(Long hits, Double min, Double max,
19 Double interval) {
20 DefaultCategoryDataset dcd = createDataset(hits, min, max, interval);
21 JFreeChart chart = ChartFactory.createLineChart( " 点击量为 " + (hits / 10000 ) + " 万时,三种销售方案随着购买率变化的折线图。 " ,
22 " 购买率(单位:0.01) " , " 销售收入(单位:10000) " , dcd,
23 PlotOrientation.VERTICAL, true , true , false );
24 Font font = new Font( " 楷体 " , Font.BOLD, 17 );
25
26 TextTitle tt = chart.getTitle();
27 tt.setFont( new Font( " 隶书 " , Font.BOLD, 25 ));
28
29 chart.getLegend().setItemFont(font);
30
31 CategoryPlot plot = chart.getCategoryPlot();
32 plot.getDomainAxis().setTickLabelFont(font);
33 plot.getDomainAxis().setLabelFont(font);
34 plot.getRangeAxis().setLabelFont(font);
35
36 plot.setNoDataMessage( " 此范围中没有数据! " );
37 plot.setNoDataMessageFont(font);
38 plot.setNoDataMessagePaint(Color.RED);
39
40 plot.setBackgroundPaint(Color.BLACK);
41
42 LineAndShapeRenderer lasr = (LineAndShapeRenderer) plot.getRenderer();
43 lasr.setBaseLinesVisible( true );
44 lasr.setBaseItemLabelPaint(Color.BLACK);
45
46 return chart;
47 }
48
49 private DefaultCategoryDataset createDataset(Long hits, Double min,
50 Double max, Double interval) {
51 DefaultCategoryDataset dcd = new DefaultCategoryDataset();
52 for (Double i = min; i <= max; i += interval) {
53 dcd.addValue(Util.solutionOneIncome(hits, i) / 10000 , " 方案一 " , i);
54 dcd.addValue(Util.solutionTwoIncome(hits, i) / 10000 , " 方案二 " , i);
55 dcd.addValue(Util.solutionThreeIncome(hits, i) / 10000 , " 方案三 " , i);
56 }
57 return dcd;
58 }
59
60 private DefaultCategoryDataset createDataset(Double purchaseRate, Long min,
61 Long max, Long interval) {
62 DefaultCategoryDataset dcd = new DefaultCategoryDataset();
63 for (Long i = min; i <= max; i += interval) {
64 dcd.addValue(Util.solutionOneIncome(i, purchaseRate) / 10000 ,
65 " 方案一 " , Long.valueOf(i / 10000 ));
66 dcd.addValue(Util.solutionTwoIncome(i, purchaseRate) / 10000 ,
67 " 方案二 " , Long.valueOf(i / 10000 ));
68 dcd.addValue(Util.solutionThreeIncome(i, purchaseRate) / 10000 ,
69 " 方案三 " , Long.valueOf(i / 10000 ));
70 }
71 return dcd;
72 }
73
74 @Override
75 public JFreeChart createChartHits(Double purchaseRate, Long min, Long max,
76 Long interval) {
77 DefaultCategoryDataset dcd = createDataset(purchaseRate, min, max,
78 interval);
79 JFreeChart chart = ChartFactory.createLineChart( " 购买率为 " + purchaseRate + " 时,三种销售方案随点击量变化的折线图。 " ,
80 " 点击数(单位:10000) " , " 销售收入(单位:10000)) " , dcd,
81 PlotOrientation.VERTICAL, true , true , false );
82 Font font = new Font( " 楷体 " , Font.BOLD, 17 );
83
84 chart.getLegend().setItemFont(font);
85
86 TextTitle tt = chart.getTitle();
87 tt.setFont( new Font( " 隶书 " , Font.BOLD, 25 ));
88
89 CategoryPlot plot = chart.getCategoryPlot();
90 plot.getDomainAxis().setTickLabelFont(font);
91 plot.getDomainAxis().setLabelFont(font);
92 plot.getRangeAxis().setLabelFont(font);
93
94 plot.setBackgroundPaint(Color.BLACK);
95
96 plot.setNoDataMessage( " 此范围中没有数据! " );
97 plot.setNoDataMessageFont(font);
98 plot.setNoDataMessagePaint(Color.RED);
99
100
101 LineAndShapeRenderer lasr = (LineAndShapeRenderer) plot.getRenderer();
102 lasr.setBaseLinesVisible( true );
103 lasr.setBaseItemLabelPaint(Color.BLACK);
104
105 return chart;
106 }
107 }

 

 

 

转载于:https://www.cnblogs.com/waibustudio/archive/2011/06/04/dssdocument.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值