SpringMVC 集成 Shiro

2019-07-01   龙德   SpringMVC   SpringMVC Shiro  

简介

  • Shiro 是 Apache 的一个安全(权限)框架

Java IO - RandomAccessFile

2019-06-27   龙德   Java   Java  

RandomAccessFile 类是专门处理文件的字节流,与其他文件类不同、也是此类最大的特点是:该类支持对文件的随机访问。

RandomAccessFile 维护着一个偏移量,也叫文件指针

当你用 RandomAccessFile 打开一个文件时,指针的值为 0

读取文件时,指针就会自动向前移动,每读取一个字节,指针就 +1

写入文件时也一样,每写入一个字节,指针就 +1

可以通过 getFilePointer 方法 获取指针,通过 seek 方法设置指针

SpringMVC 常用的注解

2019-06-24   龙德   SpringMVC   SpringMVC 注解  

@Controller

  • 作用

标注当前类是一个控制类,类名不能和注解名一样

  • 例子
@Controller // 标注这是一个控制类,类名不能和注解名一样
@RequestMapping("/book") // 访问父路径
public class BookController {
    ......
}

form 表单转 JSON,后台用 @RequestBody 接收

2019-06-23   龙德   SpringMVC   SpringMVC  

后台代码:

public Result add(@RequestBody Node node){}

前台 form 表单:

<form id="form" action="/admin/node/add" method="post" enctype="multipart/form-data">
  <div class="form-group">
    <label>名称</label>
    <input type="text" name="nodeTitle" id="nodeTitle" class="form-control node-name">
  </div>
  <div class="form-group">
    <label for="">描述</label>
    <textarea name="nodeDesc" rows="7" class="form-control node-desc"></textarea>
  </div>
  <button type="submit" id="btn" class="btnbtn-primary">提交</button>
</form>

表单的 name 要和后台对象的字段一致,否则 Spring 映射的时候会报错。

Mybtis 获取自增主键时报错

2019-06-23   龙德   MyBatis   MyBatis  

dao 层接口

int insert(@Param("node") Node node);

xml 文件

<insert id="insert" parameterType="cn.roothub.bbs.module.node.model.Node" keyProperty="nodeId" useGeneratedKeys="true">

报错信息

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorException: Error getting generated key or setting result to parameter object. Cause: org.apache.ibatis.binding.BindingException: Parameter 'nodeId' not found. Available parameters are [node, param1]

提示获取自增主键时失败,无法找到 nodeId 字段。

可是我明明有 nodeId 字段,get/set 方法也有,怎么会找不到呢?

解决方法

原来是我的 dao 层接口使用了@Param 注解,所以这时候直接指定 keyProperty 属性是无效的,这时候需要通过注解定义的对象名.属性

比如我指定的参数名是 @Param(“node”),那么 keyProperty 就要指定为 node.nodeId

keyProperty="node.nodeId"

这样就能获取到自增主键了

如果你不用 @Param 注解指定参数的名字,那么直接通过 nodeId 是可以获取到自增主键的。

MyBatis 报错 - java.lang.IllegalArgumentException-invalid comparison-java.util.Date and java.lang.String

2019-06-23   龙德   MyBatis   MyBatis  

报错信息:

java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String 

错误原因:

原因是在 Mybatis 的 xml 文件里,加入了判断空字符串的语句,无法比较 java.util.Date 类型的字段与 java.lang.String 类型的 “”

<if test="node.createDate != null and node.createDate != ''">
    create_date,
</if>

解决方法:

将判断空字符串的语句删除

<if test="node.createDate != null">
    create_date,
</if>

java.lang.OutOfMemoryError PermGen space 的解决方法

2019-06-22   龙德   Java   OutOfMemoryError  

windows 环境,将项目部署到 tomcat,用 startup.bat 启动 tomcat,启动到一半,窗口就消失了。

这时候到 logs 目录下查看 catalina.xxx.log 文件,报了一个错:

java.lang.OutOfMemoryError: PermGen space

这是内存溢出的错误,可以通过设置启动参数来解决。

Java 是值传递还是引用传递

2019-06-19   龙德   Java   Java 值传递 引用传递  

传递基本类型

看看这段代码

public static void main(String[] args) {
	int a = 10;
	foo(a);
	System.out.println(a);
}
	
public static void foo(int x){
	x = 20;
}

运行代码,输出结果:10

可以看到将 a 当做参数传递给 foo() 后,a 的值并未改变。

因为变量 a 是基本类型,声明 a 相当于向内存申请了一块空间,这一块空间保存的值是 10。将 a 传递给 foo(),只是将 a 的字面量传递,相当于 x 复制了一份 a 的值,对 x 做任何操作,都不会影响到 a ,所以这是值传递

传递引用类型

先来看第一个例子

public static void main(String[] args) {
	Dog dog = new Dog("zhangSan");
	System.out.println(dog.getName());
	foo(dog);
	System.out.println(dog.getName());
}
	
public static void foo(Dog d){
	d.setName("Lisi");
}

输出结果:

zhangSan
Lisi

可以看到 “zhangSan” 这条狗的名字改变了,变成了 “Lisi”,是不是就认为这是引用传递了呢?

当然不是的!

问题出现在这

Dog dog;

当你编写该定义时,你定义的是 Dog 类型的引用(这个引用保存在栈中),并不是 Dog 对象本身,如果你此时向 dog 发送一个消息,就会返回一个空指针异常。这是因为 dog 实际上并没有与任何事物相关联。

当你希望 dog 与一个新的对象相关联时,通常用 new 操作符来实现。

Dog dog = new Dog("zhangSan");

new 操作符在堆中创建了名为 “zhangSan” 的 Dog 对象,并将地址值(假如是 0x00)保存在名为 dog 的引用中,这样 dog 就指向了在堆中的对象,这时候使用 dog 就能向对象发送消息了。

再看下面这个例子

public static void main(String[] args){
    Dog dog = new Dog("zhangSan");
    Dog oldDog = dog;
    foo(dog);
    System.out.println(dog.getName());
    System.out.println(dog == oldDog);
}

public static void foo(Dog d){
    d = new Dog("Lisi");
}

输出结果:

zhangSan
true

将 dog 传递给 foo() 后,在 foo() 里 把它指向另一个新的对象,如果是引用传递,那么 dog 这个引用就应该重新指向这个新对象,但是从输出结果来看这是错误的。

原因是传递给 foo() 的,并不是 dog 这个引用本身,而是它所指向的在堆中对象的地址值。假如这个地址值是 0x00,那么可以这样理解,传递给 foo() 的,是 0x00。

我们在 foo() 里接受到这个地址值 0x00 后,可以给 0x00 所指向的对象发送消息,操作这个对象。形参 d 将对象的名字设置为 “Lisi” 后,dog 取出对象的名字也是 “Lisi”,这正如第一个例子所示。也就是说 d 这个形参和 dog 这个实参指向的是同一个对象,都保存着同一个地址值(0x00)。

但是将形参 d 重新指向另一个新对象,并不会对实参 dog 有任何影响,dog 还是仍然指向 0x00 这个地址值。

所以结论是,将 dog 传递给 foo(),并不是将引用本身传递,而是将引用所指向的地址值传递,也就是值传递

结论

无论是传递基本类型还是引用类型,都是值传递

参考资料

https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value?r=SearchResults

http://www.javadude.com/articles/passbyvalue.htm

Java 设计模式-观察者(发布-订阅)模式

2019-06-18   龙德   Java   Java 设计模式 观察者模式  

观察者模式简介

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

在观察者模式中有如下角色:

==Subject==:抽象主题(抽象被观察者)

接口实现,规定了增加订阅者、删除订阅者、发布主题的基本方法。

==ConcreteSubject==:具体主题(具体被观察者)

抽象主题接口的实现类,该类保存具体的订阅者(观察者)对象,当发布主题时通知订阅者去更新。

==Observer==:抽象观察者

接口实现,规定了订阅主题,取消订阅、更新主题的基本方法

==ConcrereObserver==:具体观察者

抽象观察者的实现类,当收到主题的通知时更新以获取到主题。

Java-类继承的抽象类和实现的接口有相同的方法签名

2019-06-17   龙德   Java   Java  

抽象类的抽象方法跟接口的方法相同

抽象类

public abstract class APerson {

	public abstract void speak();
}

接口

public interface IPerson {

	void speak();
}

子类

public class ZhangSan extends APerson implements IPerson {

	@Override
	public void speak() {
		System.out.println("haha");
	}

	public static void main(String[] args) {
		ZhangSan zhangSan = new ZhangSan();
		zhangSan.speak();
	}
}