demo项目开发笔录(开发技巧)

这里记录一些小技巧和注意事项:

一、

注册时给密码加密,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例如:

查询指定用户名的所有信息,数据库字段如下:

demo项目开发笔录(开发技巧)_第1张图片

实体字段如下:

demo项目开发笔录(开发技巧)_第2张图片

然后sql查询后所得实体,除了picUrl字段没有数据,其他都正常,日志也不会报错。

这种情况修改sql(加别名)如下即可:

	
		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"
	

	

三、

在开发中,大部分人喜欢使用new Date()来获取时间,使用方便,同时能获取其他信息,比如:小时,分钟等。但只是为了获取毫秒数,就可以直接使用System.currentTimeMillis()来获取,来取代new Date().getTime(),特别是在多次这样调用时,效率上会高一点。

下面是源码:

/**
     * Allocates a Date 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 Date 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('
  • '+$(domEle).children('title').text()+'
  • '); }); }, 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
    getList(@Param("username") String username, @Param("pageStart") int pageStart, @Param("pageSize") int pageSize);

    六,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引入如下:

            
            
                com.fasterxml.jackson.core
                jackson-core
                ${jackson.version}
            
            
                com.fasterxml.jackson.core
                jackson-databind
                ${jackson.version}
            
            
                com.fasterxml.jackson.core
                jackson-annotations
                ${jackson.version}
            
            
                com.fasterxml.jackson.module
                jackson-module-jaxb-annotations
                ${jackson.version}
            

    对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(){
    			@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(){
    			@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.
    	 * 
    	 * 如果JSON字符串为Null或"null"字符串, 返回Null.
    	 * 如果JSON字符串为"[]", 返回空集合.
    	 * 
    	 * 如需反序列化复杂Collection如List, 请使用fromJson(String,JavaType)
    	 * @see #fromJson(String, JavaType)
    	 */
    	public  T fromJson(String jsonString, Class 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, 先使用函數createCollectionType构造类型,然后调用本函数.
    	 * @see #createCollectionType(Class, Class...)
    	 */
    	@SuppressWarnings("unchecked")
    	public  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, 则调用constructCollectionType(ArrayList.class,MyBean.class)
    	 * HashMap, 则调用(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 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> list = Lists.newArrayList();
    		Map 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){...}





    你可能感兴趣的:(java)