这里记录一些小技巧和注意事项:
一、
注册时给密码加密,md5方式,并加“盐”,以确保不会被数据库人员识别密码,也不会被md5库被破解密码。
加密如下:
/**
* Md5加密
*/
public static String md5(String str,String salt){
return new Md5Hash(str,salt).toString();
}
第一个参数就是原密码,salt是干扰参数,计算结果是一串md5密码,此密码不可被反向逆推,所以能保证安全。
在保存时对原密码进行md5计算得到新密码然后保存即可。
使用如下:
/**
* 用户登录
*/
@RequestMapping("/login")
public String login(Users user, HttpServletRequest request){
Subject subject= SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(user.getUsername(), CryptographyUtil.md5(user.getPassword(),"gcc"));
try{
subject.login(token);
return "redirect:/index.html";
}catch(Exception e){
e.printStackTrace();
request.setAttribute("user", user);
request.setAttribute("errorMsg", "用户名或密码错误!");
return "redirect:/frontLogin.html";
}
}
在用shiro时将表单密码进行相同方式的md5计算得到对应密码,然后正常使用shiro即可。
二、
在使用mybatis时返回方式由resultMap和resultType两种,笔者原先使用前者,后来习惯使用后者,原因是可以少写点代码,但使用resultType方式返回的数据库字段如果和实体属性名字不相同时,那么得到的数据无法填充到对应字段,这样就出现了一个有趣的bug例如:
<select id="getUser" parameterType="String" resultType="Users">
select *
from t_users a where username=#{username}
</select>
查询指定用户名的所有信息,数据库字段如下:
实体字段如下:
然后sql查询后所得实体,除了picUrl字段没有数据,其他都正常,日志也不会报错。
这种情况修改sql(加别名)如下即可:
<sql id="UsersColumns">
a.id AS "id",
a.username AS "username",
a.nickname AS "nickname",
a.password AS "password",
a.company AS "company",
a.job AS "job",
a.city AS "city",
a.profile AS "profile",
a.pic_url AS "picUrl"
</sql>
<select id="getUser" parameterType="String" resultType="Users">
select
<include refid="UsersColumns"/>
from t_users a where username=#{username}
</select>
三、
在开发中,大部分人喜欢使用new Date()来获取时间,使用方便,同时能获取其他信息,比如:小时,分钟等。但只是为了获取毫秒数,就可以直接使用System.currentTimeMillis()来获取,来取代new Date().getTime(),特别是在多次这样调用时,效率上会高一点。
下面是源码:
/**
* Allocates a <code>Date</code> object and initializes it so that
* it represents the time at which it was allocated, measured to the
* nearest millisecond.
*
* @see java.lang.System#currentTimeMillis()
*/
public Date() {
this(System.currentTimeMillis());
}
/**
* Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
* represented by this <tt>Date</tt> object.
*
* @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
* represented by this date.
*/
public long getTime() {
return getTimeImpl();
}
private final long getTimeImpl() {
if (cdate != null && !cdate.isNormalized()) {
normalize();
}
return fastTime;
}
四、$.post和$.ajax
笔者原先使用$.ajax,近来觉得$.post书写更顺畅,后者的格式如下:
jQuery.post( url, [data], [callback], [type] ) :使用POST方式来进行异步请求
具体例子如下:
$.post("${pageContext.request.contextPath}/saveArticle.html",
{ 'title':title,
'typeId':typeId,
'content':content
},
function(result){
if(result.flag){
alert("发布成功");
}
},"json");
使用的感觉像是给一个方法传递四个参数,熟悉参数类型即可,而$.ajax简单的实际案例如下:
$.ajax({
type:'get',
url:'http://www.www.daimajiayuan.com/rss',
beforeSend:function(XMLHttpRequest){
//ShowLoading();
},
success:function(data,textStatus){
$('.ajax.ajaxResult').html('');
$('item',data).each(function(i,domEle){
$('.ajax.ajaxResult').append('<li>'+$(domEle).children('title').text()+'</li>');
});
},
complete:function(XMLHttpRequest,textStatus){
//HideLoading();
},
error:function(){
//请求出错处理
}
});
使用上更加繁琐,而且理解上也有不顺畅的感觉,所以如果您使用的是较为简单的异步响应可以尝试书写更流畅的$.post方式。
注:
$.post的data数据的别名如果和后台接收的对象的属性同名,则会自动赋值给对象实体。
如果使用同步请使用$.ajax; $post默认异步,改同步需要做如下处理:
$.ajaxSettings.async = false;
$.post("/saveArticle.html", data, function(result) {
// 请求处理
},"json");
$.ajaxSettings.async = true;
五、mybatis传参为多种不同类型时怎么处理
给接口方法取别名,使用如下:
List<Article> getList(@Param("username") String username, @Param("pageStart") int pageStart, @Param("pageSize") int pageSize);
<select id="getList" resultMap="ArticleResult">
SELECT *
from t_article a
WHERE a.username=#{username} ORDER BY a.postTime DESC LIMIT #{pageStart},#{pageSize}
</select>
六,json使用
@ResponseBody
@RequestMapping(value = { "/autoKpiData" })
public String autoKpiData(Master master, HttpServletRequest request) {
try {
String planId = request.getParameter("planId");
String flag=kpiDataService.autoKpiData(master,planId);
String json = JsonMapper.toJsonString(master);
Master master = (Master) JsonMapper.fromJsonString(json,Master.class);
return flag;
} catch (Exception e) {
return e.getMessage();
}
}
1,使用@ResponseBody,返回的数据不是html标签的页面,而是其他某种格式的数据(如json、xml等),可以简化原始的写法,如PrintWriter的处理,如下:
JSONObject result = new JSONObject();
result.put("flag", true);
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
out.println(result.toString());
out.flush();
out.close();
2,通过JsonMapper.toJsonString()将实体类型转换成json类型,可以通过ajax的回调对象result,对象.属性名来取值。
在页面取到规则的(对应属性名字)json值时也可以通过JsonMapper.fromJsonString来将json数据填充到实体属性里。
mavne引入如下:
<!-- jackson json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
对ObjectMapper简单封装的类如下:
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* 简单封装Jackson,实现JSON String<->Java Object的Mapper.
* 封装不同的输出风格, 使用不同的builder函数创建实例.
*/
public class JsonMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
private static JsonMapper mapper;
public JsonMapper() {
this(Include.NON_EMPTY);
}
public JsonMapper(Include include) {
// 设置输出时包含属性的风格
if (include != null) {
this.setSerializationInclusion(include);
}
// 允许单引号、允许不带引号的字段名称
this.enableSimple();
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 空值处理为空串
this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){
@Override
public void serialize(Object value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeString("");
}
});
// 进行HTML解码。
this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){
@Override
public void serialize(String value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
}
}));
// 设置时区
this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00")
}
/**
* 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
*/
public static JsonMapper getInstance() {
if (mapper == null){
mapper = new JsonMapper().enableSimple();
}
return mapper;
}
/**
* 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
*/
public static JsonMapper nonDefaultMapper() {
if (mapper == null){
mapper = new JsonMapper(Include.NON_DEFAULT);
}
return mapper;
}
/**
* Object可以是POJO,也可以是Collection或数组。
* 如果对象为Null, 返回"null".
* 如果集合为空集合, 返回"[]".
*/
public String toJson(Object object) {
try {
return this.writeValueAsString(object);
} catch (IOException e) {
logger.warn("write to json string error:" + object, e);
return null;
}
}
/**
* 反序列化POJO或简单Collection如List<String>.
*
* 如果JSON字符串为Null或"null"字符串, 返回Null.
* 如果JSON字符串为"[]", 返回空集合.
*
* 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
* @see #fromJson(String, JavaType)
*/
public <T> T fromJson(String jsonString, Class<T> clazz) {
if (StringUtils.isEmpty(jsonString)) {
return null;
}
try {
return this.readValue(jsonString, clazz);
} catch (IOException e) {
logger.warn("parse json string error:" + jsonString, e);
return null;
}
}
/**
* 反序列化复杂Collection如List<Bean>, 先使用函數createCollectionType构造类型,然后调用本函数.
* @see #createCollectionType(Class, Class...)
*/
@SuppressWarnings("unchecked")
public <T> T fromJson(String jsonString, JavaType javaType) {
if (StringUtils.isEmpty(jsonString)) {
return null;
}
try {
return (T) this.readValue(jsonString, javaType);
} catch (IOException e) {
logger.warn("parse json string error:" + jsonString, e);
e.printStackTrace();
return null;
}
}
/**
* 構造泛型的Collection Type如:
* ArrayList<MyBean>, 则调用constructCollectionType(ArrayList.class,MyBean.class)
* HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class)
*/
public JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return this.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
/**
* 當JSON裡只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性.
*/
@SuppressWarnings("unchecked")
public <T> T update(String jsonString, T object) {
try {
return (T) this.readerForUpdating(object).readValue(jsonString);
} catch (JsonProcessingException e) {
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
} catch (IOException e) {
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
}
return null;
}
/**
* 輸出JSONP格式數據.
*/
public String toJsonP(String functionName, Object object) {
return toJson(new JSONPObject(functionName, object));
}
/**
* 設定是否使用Enum的toString函數來讀寫Enum,
* 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
* 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
*/
public JsonMapper enableEnumUseToString() {
this.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
this.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
return this;
}
/**
* 支持使用Jaxb的Annotation,使得POJO上的annotation不用与Jackson耦合。
* 默认会先查找jaxb的annotation,如果找不到再找jackson的。
*/
public JsonMapper enableJaxbAnnotation() {
JaxbAnnotationModule module = new JaxbAnnotationModule();
this.registerModule(module);
return this;
}
/**
* 允许单引号
* 允许不带引号的字段名称
*/
public JsonMapper enableSimple() {
this.configure(Feature.ALLOW_SINGLE_QUOTES, true);
this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
return this;
}
/**
* 取出Mapper做进一步的设置或使用其他序列化API.
*/
public ObjectMapper getMapper() {
return this;
}
/**
* 对象转换为JSON字符串
* @param object
* @return
*/
public static String toJsonString(Object object){
return JsonMapper.getInstance().toJson(object);
}
/**
* JSON字符串转换为对象
* @param jsonString
* @param clazz
* @return
*/
public static Object fromJsonString(String jsonString, Class<?> clazz){
return JsonMapper.getInstance().fromJson(jsonString, clazz);
}
/**
* 测试
*/
public static void main(String[] args) {
List<Map<String, Object>> list = Lists.newArrayList();
Map<String, Object> map = Maps.newHashMap();
map.put("id", 1);
map.put("pId", -1);
map.put("name", "根节点");
list.add(map);
map = Maps.newHashMap();
map.put("id", 2);
map.put("pId", 1);
map.put("name", "你好");
map.put("open", true);
list.add(map);
String json = JsonMapper.getInstance().toJson(list);
System.out.println(json);
}
}
3,data传值方式如下时:
$.post(
"${ctx}/pa/in/kpiData/autoKpiData",
{
'id':masterId,
'planId':planId,
'groupId':groupId
},
function (result) {
if("Success"==result){
$("#btnSubmit").click();
window.setTimeout(function () { $.jBox.tip('操作成功!', 'success'); }, 500)
}else{
window.setTimeout(function () { $.jBox.tip('操作失败,请确认是否已有考核计划在运行!', 'error'); }, 1000)
}
},
"json"
)
spring也可以将属性名对应的数据填充到实体内:
public String autoKpiData(Master master, HttpServletResponse response,HttpServletRequest request){...}