SpringMVC中Interceptor和自定义filter的典型应用

今天写写老夫最擅长的Java web,在Java web中Interceptor和filter应用十分广泛,今天就写一个在我们的项目中的一个最基本的应用,过滤或者拦截未登录用户访问某些资源。 SpringMVC中Interceptor SpringMVC 中的Interceptor 拦截器是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆等等。今天就写一个Interceptor在开发中的典型应用:某一系统某些方法肯定是需要用户登陆才能访问的,而另外一些肯定不需要用户登陆就能访问(这样的例子很多,老夫就不举例说明了),那么我们怎么做,才能做到呢?这个时候Interceptor就派上用场了,下面是一个小例子,供参考: spring-servlet.xml核心代码如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <mvc:interceptors> <bean id="permissionInterceptor" class="cn.bridgeli.demo.interceptor.PermissionInterceptor"></bean> </mvc:interceptors> &#8230;&#8230; </beans> 对应的Interceptor的实现: package cn.bridgeli.demo.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndViewDefiningException; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.util.UrlPathHelper; import cn.bridgeli.demo.entity.User; public class PermissionInterceptor extends HandlerInterceptorAdapter { private UrlPathHelper urlPathHelper = new UrlPathHelper(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { User user = (User) request.getSession().getAttribute("USER"); String url = urlPathHelper.getLookupPathForRequest(request); int flag = url.indexOf("/admin/"); if (user == null && flag != -1) { ModelAndView mav = new ModelAndView("error/permissionerror"); mav.addObject("ERRORMSG", "对不起,您没有登录,无法使用该功能!"); throw new ModelAndViewDefiningException(mav); } return true; } } 关于InterceptorAdapter的更多用法,大家可以参考http://haohaoxuexi.iteye.com/blog/1750680,老夫以为这篇文章说的相对比较详细易懂,除此之外,我们还可以通过自定义filter来实现; ...

March 8, 2015 · 2 min · 220 words · Bridge Li

Android之BroadcastReceiver初步

今天接着写自己学习Android开发的笔记,这次记录一下BroadcastReceiver,看这个名字我们就知道他是干嘛的了,广播接收器吗,那么他有什么用呢?老夫以为用途还是比较大的,例如用户玩游戏的时候,我们必须在监听到手机来电事件、短信事件之后,暂停游戏保存游戏当时的数据,等用户接完电话、处理完短信之后再接着玩游戏。 之前我曾经说过,Android的四大组件都需要注册,方能使用,那么broadcast作为四大组件之一,也肯定需要注册,不同于其他组件的是broadcast有两种注册方法: 1,在AndroidManifest.xml中进行注册; 2.在代码中进行注册 既然有这两种注册方式,那么他们肯定会有区别,他们的区别又是什么呢? 在AndroidManifest.xml中进行注册,属于全局性的,也就是说无论你这个应用是否在运行,只要有某一他监听的广播被发出,那么他都会被监听到,这个的典型应用就是手机的黑名单功能,无论这个应用是否在运行,应该都可以监听用户手机的来电,进行过滤;而在代码中进行注册呢?肯定就不是全局的了,只有你这个应用启动的时候,他才会监听他所监听的事件,这个的典型应用就是,用于更新应用的UI,在activity启动的时候注册BroadcastReceiver,在activity不可见之后取消注册,因为activity不可见的时候更新UI,除了浪费CPU浪费电之外没有任何意义,好,下面我们就看看这两种方法的实现。 1,在AndroidManifest.xml中进行注册 package cn.bridgeli.demo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener { private Button send = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); send = (Button) findViewById(R.id.send); send.setText("Send Broadcast"); send.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.start: Intent intent = new Intent(); intent.setAction(Intent.ACTION_EDIT); sendBroadcast(intent); break; default: break; } } } 对应的布局文件其实很简单 ...

March 1, 2015 · 2 min · 232 words · Bridge Li

别人抢红包,程序猿来探讨微信红包的算法实现

曾经在公司写过一个类似于微信抢红包的功能,当时由于不会写,各种纠结,虽然最终实现了功能,但也仅仅是实现功能而已,像腾讯这么牛的公司肯定不是那样的,那么腾讯是怎么实现的呢?一直很好奇,但一直不得要领,今天偶然发现一篇文章,作者用很简单的算法,算是比较完美的解决了这个问题,说是完美,因为该算法满足了: 1、每个人都要能够领取到红包; 2、每个人领取到的红包金额总和=总金额; 3、每个人领取到的红包金额不等,但也不能差的太离谱,不然就没趣味; 4、算法一定要简单,不然对不起腾讯这个招牌; 但由于原文是Python写的(老夫的推测,因为老夫并不会Python,本文底部注有链接,感兴趣的可以看看),老夫改为由Java实现,当然介于水平,实现的可能并不好,写在这里算是抛砖引玉,如果有牛人写出来更好的,欢迎留言交流 package cn.bridgeli.hongbao; public class HongBao { public static void fenPei(double totalMoney, int totalPerson) { double min = 0.01; for (int i = 1; i < totalPerson; i++) { // 随机安全上限,同时扩大 100 倍 double safeTotal = ((totalMoney &#8211; (totalPerson &#8211; i) \* min) / (totalPerson &#8211; i)) \* 100; // 生成随机钱数 double money = Math.floor(Math.random() * safeTotal + 1.0) / 100; totalMoney -= money; System.out.println("第" + i + "个红包:" + money + " 元"); } System.out.println("第" + totalPerson + "个红包:" + roundDouble(totalMoney) + " 元"); } // 四舍五入 private static Double roundDouble(double val) { Double ret = null; try { // 2 表示保留两位小数 double factor = Math.pow(10, 2); ret = Math.floor(val * factor + 0.5) / factor; } catch (Exception e) { e.printStackTrace(); } return ret; } } 参考资料:http://mp.weixin.qq.com/s?__biz=MjM5OTA1MDUyMA==&mid=204349860&idx=2&sn=0a3433ff34c08dca5c47f7d97301e118#rd

February 25, 2015 · 1 min · 134 words · Bridge Li

Android之Service

今天记录一下老夫对Service的理解,先看一下Service的概念,即Service是什么不是什么,那Service是什么呢? Service是Android的四大组件之一,可以长时间在后台运行; Service不提供界面交互,即Service不像activity一样,有一个界面做展示; 即便用户跳转至另一个应用后,Service仍旧在后台运行; 任意应用组件都可以绑定一个服务,甚至可以用来完成进程间通讯的任务; 可以使用Service更新ContentProvider,发送Intent以及启动系统的通知等等; 那Service不是什么呢? Service不是一个单独的进程; Service不是一个线程!!!(即Service运行于主线程中,根据Service的概念,这个应该有很多人怀疑,持怀疑态度的可以打一下线程号,比较简单,老夫就不多做赘述了) 看完Service是什么和不是什么之后,我们来看看什么时候需要用Service呢?Service一般是在后台做一些费力费时的任务(老夫窃以为和西游记中的沙僧差不多,默默无闻,任劳任怨),例如:下载文件、播放音乐、文件I/O等。 既然在这些时候需要用Service,那么我们怎么启动一个Service呢?启动一个Service用两种方式,分别是startService()和bindService(),那么他们之间又有什么区别和应用于什么场合呢? 首先来看startService(),一旦某个组件start一个Service后,Service开始独立运行,不在与原来的组件产生任何关系,如果想要停止Service,必须手动停止,所以其适用于开启下载、播放音乐之类的; 下面我们再看看bindService(),某个组件bind一个Service后,Service为组件提供一个接口,近似于客户端,会进行交互,当所有bind的组件都结束后,Service会自动停止,有很多系统服务都被系统封装了,例如传感器、定位等。 看了一大堆理论之后,我们来看看怎么启动一个service: 一、startService(),代码如下: MainActivity用来启动一个Service, package cn.bridgeli.demo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener { private Button start = null; private Button stop = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); start = (Button) findViewById(R.id.start); start.setText("Start Service"); start.setOnClickListener(this); stop = (Button) findViewById(R.id.stop); stop.setText("Stop Service"); stop.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.start: Intent startService = new Intent(); startService.setClass(MainActivity.this, MainService.class); startService(startService); break; case R.id.stop: Intent stopService = new Intent(); stopService.setClass(MainActivity.this, MainService.class); stopService(stopService); break; default: break; } } } 对应的布局文件activity_main: ...

February 8, 2015 · 3 min · 448 words · Bridge Li

Android之Activity之间的参数传递

前面写了很多activity的东西,什么生命周期之类、常用控件以及这些控件怎么布局之类的,今天从另外一个角度在看activity:一个应用其实就是不同activity的切换,然后展示一些数据给用户,但是不同的activity之前肯定有着联系,那么他们之间怎么联系呢?说白了就是他们之间的参数是如何传递的呢?在讲不同的activity之间相互传参之前,我们先看这样两个问题:①:我们有时候需要从一个activity跳转到另一个activity,并且同时把参数带过去,然后一般就没有第一个activity啥事了,这个很常见所以就不举例子了,我们暂且称这一种为:普通的参数传递;②:有些时候呢,却不是这样,我们需要在第一个activity中打开第二个activity,在第二个activity中选取一个内容后,把我们选取的参数带回第一个activity,然后在第一个activity中处理带回来的参数,例如:我们在上传头像时,我们在第一个activity中,打开第二个activity,然后在第二个activity中,选取图片、裁剪图片,然后把处理好之后的图片带回到第一个activity,我们暂且称这种叫:关心结果的参数传递。 在明白有这两种需求之后,我们发现不同的activity之间参数传递其实很简单,不同的activity之间传递参数是依靠一个对象:android.content.Intent,只要有这个对象就可以满足我们在不同的activity之间传递参数的需求了。下面就让我们结合这两种情况,看看不同activity之间参数如何传递。 一、普通的参数传递 废话不多说,先看例子: 主activity的代码如下: package cn.bridgeli.demo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private EditText factorOne = null; private TextView symbol = null; private EditText factorTwo = null; private Button calc = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); factorOne = (EditText) findViewById(R.id.factorOne); symbol = (TextView) findViewById(R.id.symbol); symbol.setText("乘以"); factorTwo = (EditText) findViewById(R.id.factorTwo); calc = (Button) findViewById(R.id.calc); calc.setText("计算"); calc.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { String firstNum = factorOne.getText().toString(); String secondNum = factorTwo.getText().toString(); Intent intent = new Intent(); intent.setClass(MainActivity.this, ResultActivity.class); intent.putExtra("firstNum", firstNum); intent.putExtra("secondNum", secondNum); startActivity(intent); } }); } } 其对应的布局文件:activity_main.xml ...

February 1, 2015 · 3 min · 533 words · Bridge Li

Activity之常见控件(二)

上一篇文章中,记录一些在activity常见的控件,今天再记录也是很常见的控件,但其用法相对来说,要更复杂一些,直接来例子: ListView ListView一看名字就知道了,用于在activity中展示一个list,例如我们要查询出所有的用户并在activity中展示出来,那么此时ListView就派上用场了;首先看Activity的代码: package cn.bridgeli.demo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.ListActivity; import android.os.Bundle; import android.view.View; import android.widget.ListView; import android.widget.SimpleAdapter; public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); List<Map<String, String>> list = new ArrayList<Map<String,String>>(); Map<String, String> map1 = new HashMap<String, String>(); Map<String, String> map2 = new HashMap<String, String>(); Map<String, String> map3 = new HashMap<String, String>(); map1.put("username", "test1"); map1.put("user_ip", "192.168.0.1"); map2.put("username", "test2"); map2.put("user_ip", "192.168.0.2"); map3.put("username", "test3"); map3.put("user_ip", "192.168.0.3"); list.add(map1); list.add(map2); list.add(map3); SimpleAdapter listAdapter = new SimpleAdapter(this, list, R.layout.item, new String[]{"username", "user_ip"}, new int[]{R.id.username, R.id.user_ip}); setListAdapter(listAdapter); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); System.out.println("position === " + position); System.out.println("id === " + id); } } 这里面用到了两个布局文件,一个是主布局文件activity_main.xml,比较简单,代码如下: ...

January 25, 2015 · 4 min · 823 words · Bridge Li

Activity之常见布局初步

前一篇博客记录了在activity中有哪些控件可供我们使用,既然牵涉到控件,那么肯定会牵涉到控件的布局,也就是在activity中怎么摆放这些东西,我们先看看activity的布局方式有哪些:LinearLayout线性布局、TableLayout表格布局、RelativeLayout相对布局、AbsoluteLayout绝对布局、FrameLayout帧布局等五种,各有各的用途和用法,其中老夫认为最常用的是前三种,最最常用的应该就是前两种了,今天我们就介绍一下前三种的用法。 首先看第一个也是非常常见的也是非常简单的LinearLayout线性布局方式,布局文件为: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!&#8211; android:id 为控件指定相应的ID android:text 指定控件中显示的文字,需要注意的是:这里最好使用strings.xml android:gravity 指定控件中内容的基本位置,比如居中、靠左等 android:textSize 指定控件中字体的大小 android:background 指定控件的背景色,使用RGB命名法 android:width 指定控件的宽度 android:height 指定控件的高度 android:layout_width 和父控件的关系,例如是匹配内容还是在水平方向上填满父控件 android:layout_height 和父控件的关系,例如是匹配内容还是在垂直方向上填满父控件 android:padding* 指定控件的内边距,也就是说控件中内容 android:singleLine= 布尔值,如果为真,则控件中的内容将在一行中显示 &#8211;> <TextView android:id="@+id/firstTextView" android:text="第一行" android:gravity="center_vertical" android:textSize="20pt" android:background="#ff0000" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dip" android:paddingTop="20dip" android:paddingRight="30dip" android:paddingBottom="40dip" android:singleLine="false" /> <TextView android:id="@+id/secondTextView" android:text="第二行" android:gravity="center_vertical" android:textSize="30pt" android:background="#00ff00" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 其中LinearLayout表示采用线性布局方式,第五行:android:orientation=”vertical”表示是在水平方向还是在垂直方向上线性布局,注释中为该元素设置样式的各种含义。 需要说明的是,LinearLayout是可以嵌套的,下面给出一个例子: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:id="@+id/firstTextView" android:text="第一行" android:gravity="center_vertical" android:textSize="20pt" android:background="#ff0000" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dip" android:paddingTop="20dip" android:paddingRight="30dip" android:paddingBottom="40dip" android:singleLine="false" /> <TextView android:id="@+id/secondTextView" android:text="第二行" android:gravity="center_vertical" android:textSize="30pt" android:background="#00ff00" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:id="@+id/firstTextView" android:text="第一行" android:gravity="center_vertical" android:textSize="20pt" android:background="#ff0000" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dip" android:paddingTop="20dip" android:paddingRight="30dip" android:paddingBottom="40dip" android:singleLine="false" /> <TextView android:id="@+id/secondTextView" android:text="第二行" android:gravity="center_vertical" android:textSize="30pt" android:background="#00ff00" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout> 关于嵌套需要说明的是,1. 最外层的android:orientation=”vertical”表示内部所有的LinearLayout的布局方式,当然每一个LinearLayout的android:orientation=”vertical”表明自己内部每一个元素的布局方式;2. 每一个LinearLayout的android:layout_weight=”1″表示该LinearLayout的权重,即该LinearLayout在所有空间中所占的比例。最后需要说明的是,这个我是把第一个文件直接拷过去的,所以ID有重复,大家记得改一下 下面我们看第二种布局方式:TableLayout表格布局,其中我个人感觉这种布局方式用的应该不是很多,下面我们看看其布局文件: ...

January 18, 2015 · 2 min · 252 words · Bridge Li

Android之常见控件

在我们开发Android的时候,有各种各样常见的控件供我们使用,今天就记录一下这些常见的控件有哪些,其实他们的用法大多一样,希望能举一反三, 第一个常见的控件恐怕就是EditText、TextView、Button,使用的例子如下: activity_main.xml布局文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/factorOne" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/symbol" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:id="@+id/factorTwo" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/calc" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> 对应的activity: package cn.bridgeli.demo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private EditText factorOne = null; private TextView symbol = null; private EditText factorTwo = null; private Button calc = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); factorOne = (EditText) findViewById(R.id.factorOne); symbol = (TextView) findViewById(R.id.symbol); factorTwo = (EditText) findViewById(R.id.factorTwo); calc = (Button) findViewById(R.id.calc); symbol.setText(R.string.symbol); calc.setText(R.string.calc); calc.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { String firstNum = factorOne.getText().toString(); String secondNum = factorTwo.getText().toString(); Intent intent = new Intent(); intent.setClass(MainActivity.this, ResultActivity.class); intent.putExtra("firstNum", firstNum); intent.putExtra("secondNum", secondNum); startActivity(intent); } }); } } result.xml布局文件就比较简单了,只有一个TextView ...

January 11, 2015 · 3 min · 563 words · Bridge Li

Activity之生命周期

这几天没事,自学了一下Android的开发,今天记录一下activity的生命周期,在写之前,我们先看一下,Google官方的文档,窃以为这个说的已经比较清楚明白了: 从这张图,我们清楚无误的看到,activity的生命周期方法执行顺序为:onCreate()–>onStart()–>onResume()–>onPause()–>onStop()–>onRestart()–>ondestory() 但是口说无凭,我们从一个例子中说明问题: 第一个activity: package cn.bridgeli.lifecycle; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button button = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); ButtonListener buttonListener = new ButtonListener(); button.setOnClickListener(buttonListener); System.out.println("First activity onCreate"); } class ButtonListener implements OnClickListener{ @Override public void onClick(View arg0) { Intent intent = new Intent(); intent.setClass(MainActivity.this, SecondActivity.class); startActivity(intent); } } @Override protected void onDestroy() { super.onDestroy(); System.out.println("First activity onDestroy"); } @Override protected void onPause() { System.out.println("First activity onPause"); super.onPause(); } @Override protected void onResume() { super.onResume(); System.out.println("First activity onResume"); } @Override protected void onStart() { super.onStart(); System.out.println("First activity onStart"); } @Override protected void onStop() { super.onStop(); System.out.println("First activity onStop"); } @Override protected void onRestart() { super.onRestart(); System.out.println("First activity onRestart"); } } 第二个activity: ...

January 4, 2015 · 2 min · 230 words · Bridge Li

软件属性小结

一. 功能属性 Use Story和Use Case 功能的三个要素 ①. 参与者 用户、角色、用户和角色的关系 ②. 流程 整体流程、页面操作流程 ③. 表单(UI) 正确性(精确性) 二. 决定与架构 权衡软件质量属性 架构元素 ①. 架构(决定)过程 ②. 架构(决定)产物 架构(架构元素集合) 三. 质量属性(非功能性属性) 开发期质量属性 ①. 易理解性和可读性 所有烦人工作成果(如需求文档、设计文档、code等)易读、易理解,可以提高团队开发性率,降低维护成本 考虑的因素:拒绝啰里啰嗦、复杂问题简单化、拒绝学术化、严格遵守codestyle(一旦定下来,团队所有成员必须无条件遵守!!!) ②. 可扩展性 可扩展性是软件适应变化的能力,在软件开发过程中变化时司空见惯的,如需求、设计、算法的改进,程序的变化的等等。 考虑的因素:增量开发、小型大型软件、是否有下一个版本 ③. 可重用性 重复利用软件的中某一个组件(如文档模板、架构框架、代码)的能力 考虑的因素:架构(框架)重用、模块重用、重用与分层 ④. 可测试性 软件测试的难易程度,软件的可测试性是指软件发生故障并隔离、定位其故障的能力特性,以及在一定的时间和成本的前提下,进行测试设计、测试执行的能力,例如Controller层不要和request、response等耦合、表单等要有Id(为了自动化测试)等 ⑤. 可维护性 可维护性是指理解、改正、改动、改进软件的难易程度,影响可维护性的因素有:可理解性、可测试性、可扩展性 改正性维护:软件在使用中发现了隐藏的错误后,为了诊断和改正这个隐藏错误而修改软件的活动 适应性维护:为了适应变化了的环境而修改软件的活动,如:数据库、操作系统、服务器网络带宽等 完善性维护:为了扩充或完善原有软件功能或性能而改动软件的活动 预防性维护:为了提高软件的可维护性和可靠性,为未来的进一步改进打下基础而修改的活动 ⑥. 可移植性 是指软件不经修改或稍加修改就可以运行于不同软硬件环境(CPU、OS)的能力,主要是代码的可移植性 考虑的因素:硬件之间、数据库之间 ⑦. 兼容性 不同软件或新老版本之间交换信息的能力 考虑的因素:版本之间的兼容、软件之间的兼容,例如:老的客户端能否调用新的服务器版本的API,office和wps兼容性问题(这个存在强势问题,例如微软比较强大、用户比较多,我们就可以不兼容你们金山) 运行期质量属性 ①. 性能 性能通常是指软件的“时间-空间”效率,而不是软件的运行速度。人们总希望软件的运行速度高些,并且占用资源少些,一言以蔽之:既要马儿跑得快,又要马儿吃得少,即性价比最高。 性能优化的关键是:找出限制性能的瓶颈,原则是:管理好自己,控制好别人,那么自己是谁?别人有是谁呢?自己一般是进程(拥有)、内存(分配给自己的)、程序;别人一般是:数据库、文件、其他系统、网络。 控制别人,对外资源(数据库连接、文件流、socket等)一定要关闭,而且在finally里面关闭,当然一些连接可以使用池的概念。 管理好自己,数据库调优、JVM调优、堆栈内存大小的设置等这是一个很大的概念,希望将来能有一篇专门的文章来写这个,其实关于这个网上的资料也挺多的,大家可以自己搜一些来自学一下 ②. 安全性 这里的安全性是指信息安全,英文原文是指:security而不是safety,安全性是指防止系统被非法入侵的能力,即属于技术问题又属于安全问题。那么什么样的系统是安全的呢?一般的,如果黑客为非法入侵花费的代价(时间、费用、风险等等)高于得到的好处,那么这样的系统可以认为是安全的 考虑的因素:同源策略、SQL输入、跨站脚本攻击、跨站请求伪造、加密解密技术、API安全性,这些每一个都是一门学问,大家可以自己都一些资料,自己去学习一下 ③. 易用性 用户(是指最终用户)使用软件的容易程度,最终用户并不关心软件是怎么实现的,他们只关心UI、操作的方便性、流程的简易程度 ④. 可用性 这个比较难描述,只要出现问题就是不可用的,例如:银行系统,A用户向B用户转账,A的钱扣了,B却没收到等等 ⑤. 可伸缩性 代表一种弹性,在系统扩展成长的过程中,软件能够保证旺盛的生命力,通过很少的改动甚至只是硬件设备的添置,就能实现整个系统处理能力的线性增长,实现高吞吐量和低延迟的高性能。 考虑的因素:数据库是否支持集群、web服务器的集群(session本地问题、文件本地化问题) ⑥. 互操作性 一般是指对外提供API的调用难易,例如一些开放平台 ⑦. 可靠性 在给定的条件下,在给定的时间内,系统不发生故障的概率,可靠性问题一出现一般是很难发现的,他出现无规律,时隐时现 ⑧. 健壮性 是指在异常情况下,软件能够正常工作的能力 异常:与预期产生不同结果都叫异常,预期:和用户的预期、QA的预期、需求文档的预期(主要是这个,即运行结果和需求文档描述不一致) 例如:用户注册输入一个已存在的用户名,怎么做?(应该提示用户,不能抱一个505错误)、数据库宕机、网络慢等情形下该怎么做? 容错能力:异常发生后,软件能否正常运行,例如:数据库主从备份、多服务器集群,用户输入错误的数据,能提示用户 恢复能力:例如数据备份,当一个数据库宕机之后,另一个备份数据库能自己立马启动,接下宕机服务器的任务继续工作

December 28, 2014 · 1 min · 91 words · Bridge Li