SSM架构商城项目(三)

3.3. 用户-登录-控制器层

已知登录功能会抛出UserNotFoundExceptionPasswordNotMatchException,而业务异常的处理都是在BaseController中处理的,所以,可以先直接在BaseController中对这2种异常进行处理!

接下来,分析处理登录数据的请求:

请求路径:/user/handle_login.do
请求类型:POST
请求参数:username(*), password(*)
响应方式:ResponseBody
是否拦截:否,不需要登录即可使用

则,在UserController添加方法:

@RequestMapping(value="/handle_login.do")
@ResponseBody
public ResponseResult handleLogin(
    @RequestParam("username") String username,
    @RequestParam("password") String password,
    HttpSession session) {
    // 调用业务层对象的User login(String, String)方法,并获取返回值
    // 将uid和username封装到Session中
    // 返回ResponseResult对象
}

测试,例如http://localhost:8080/TeduStore/user/handle_login.do?username=aaa&password=bbb

3.4. 用户-登录-前端页面

web/login.html中找到“登录”按钮的点击处理,发出AJAX请求并获取结果:

$('#bt-login').click(function(){
    var url = "../user/handle_login.do";
    var username = $("#username").val();
    var password = $("#password").val();
    var data = "username=" + username 
            + "&password=" + password;
    $.ajax({
        "url": url,
        "data": data,
        "type": "post",
        "dataType": "json",
        "success": function(json) {
            if (json.state == 200) {
                alert("登录成功!");
            } else if (json.state == 402) {
                alert("登录失败!" + json.message);
            } else if (json.state == 403) {
                alert("登录失败!" + json.message);
            } else {
                alert("莫名其妙!!!");
            }
        }
    });
});

4. 用户-更改密码

4.1. 用户-更改密码-持久层

由于持久层是不考虑业务问题,只负责最后的数据处理,针对这个功能,需要做的处理包含:验证原密码(查询)、执行更新密码(修改)。

则需要在UserMapper.java接口中声明抽象方法:

User getUserById(Integer uid); // 查询出密码、盐、用户名、性别、手机、邮箱、头像……即所有基本信息

Integer changePassword(
    @Param("uid") Integer uid, 
    @Param("password") String password);

然后,在UserMapper.xml中配置映射:

SELECT username, password... FROM t_user WHERE id=?

UPDATE t_user SET password=? WHERE id=?

完成后测试。

4.2. 用户-更改密码-业务层

首先,应该在业务层中添加与持久层相同的2个方法,不过,关于修改密码的方法应该将返回值修改为void,并声明抛出UpdateDataException

void changePassword(Integer uid, String password)
    throws UpdateDataException;

然后,在业务层添加最终需要被控制器调用的方法:

void changePasswordByOldPassword(
    Integer uid, String oldPassword, String newPassword)
        throws UserNotFoundException,
            PasswordNotMatchException, 
                UpdateDataException;

接下来,在实现类中实现这些抽象方法。

完成后,执行单元测试。

4.3. 用户-更改密码-控制器层

已知更改密码功能会抛出UpdateDataException,而业务异常的处理都是在BaseController中处理的,所以,可以先直接在BaseController中对这种异常进行处理!

接下来,分析处理更改密码数据的请求:

请求路径:/user/handle_change_password.do
请求类型:POST
请求参数:uid(*,session), old_password(*), new_password(*)
响应方式:ResponseBody
是否拦截:是,请检查拦截器配置,拦截当前路径

则,在UserController添加方法:

@RequestMapping(value="/handle_change_password.do")
@ResponseBody
public ResponseResult handleChangePassword(
    @RequestParam("old_password") String oldPassword,
    @RequestParam("new_password") String newPassword,
    HttpSession session) {
    // 从session获取uid
    // 执行修改
    // 返回
}

测试,先打开登录页,完成登录,然后再通过浏览器地址栏来访问,例如http://localhost:8080/TeduStore/user/handle_change_password.do?old_password=xxx&new_password=xxx

4.4. 用户-更改密码-前端页面

(周一再说)


其它

1. @Autowired和@Resource有什么区别

以上2个注解都是用于自动装配的,即:当需要为某个属性自动注入时,在属性之前添加以上2个注解中的任意一个都可以!

@Autowired是Spring框架中定义的注解,是根据类型实现自动装配的,即byType

@Resource是javax中定义的注解,是优先根据名称实现自动装配的,即优先byName,如果装配失败,则会根据类型来实现自动装配,即byType

由于目前主流的开发模式中,WEB应用程序都是有javax的,而且,都会使用SSM框架,所以,以上2个注解在任何一个项目中都是可以直接使用的,无须额外添加jar包或依赖!

而且,在实际开发中,某个接口的实现类应该是唯一的!例如IUserService接口就只有1个UserServiceImpl实现类,所以,根据类型来装配是完全没有问题的!甚至,在实现类上,添加例如@Service注解时,也应该(不是必须的)设置合理的Bean id,例如@Service("userService"),结合private IUserSerivce userService;的属性声明,这样的Bean id也满足了根据名称来装配的需求,所以,这2种注解,在使用时,使用任何一个都是OK的!

使用注解实现的自动装配,不需要属性有SET方法,都是通过反射技术为属性直接赋值的!

2. 面向对象的特征

封装

先“装”了再“封”,即是封装。

例如:

public class Person {
    Integer age;
    String name;
}

就是把2个属性“装”在1个类型中。

简单的“装”起来,可能存在数据不安全的问题(不按我们设定的规则来创建或修改数据,都是不安全的),例如:

Person p = new Person();
p.age = 9527; // 数据的赋值过程不安全

为了限制随意修改数据,则:

private Integer age;

这样做法就是“封”,同时,为了使得该数据仍是可以被访问的:

public void setAge(Integer age) {
    this.age = age;
}

由于方法是可以设置相关逻辑的:

public void setAge(Integer age) {
    if (age > 18 && age < 60) {
        this.age = age;
    }
}

并且,为了使得可以获取数据的值,还应该:

public Integer getAge() {
    return age;
}

封装的好处在于:便于数据的传递,保证数据的安全,对于方法而言,对外隐藏了方法体中的实现过程,使得方法的调用者只用关心调用方式和执行结果即可。

封装不仅仅是对类的成员进行封装,类本身也是可以封装的:

```
-- public class Car
-- class Audi extends Car
-- public class CarFactory > public static Car getCar() 
```

在以上结果中,AudiCar的子类,没有使用public修饰这个类,则该类在com.company.spring包以外是无法识别,但是,Audi可以实现的功能都在Car中定义了,当需要对象时,可以通过CarFactory.getCar()方法获取对象,这就是对Audi类的封装,与此前对属性的封装一样,先缩小其权限范围,使得它不能被随意访问,同时,还提供公开的访问数据的方式,隐藏了对象的创建过程!

继承

继承是一种利用已有的类(父类),快速创建新的类(子类)的机制!

Java是一门单继承的语言,所以,每个类都有且仅有1个直接父类(Object除外)。

继承的本质是extends,即“扩展”,即:子类在父类的基础上扩展出了更多的属性、方法等……

每次创建子类的对象时,都会先创建父类的对象!

当继承后,子类拥有父类中所有的属性和方法(除了私有成员、构造方法、static成员)。

多态

多态指的是多种形态,即编译期和运行期是不同的形态,例如:

Object obj = new Random();

以上代码中,Object obj表示声明变量,该代码是编译期(编译器把.java文件编译成.class文件时)就可以确定的,也就是确定了obj变量是Object的,而new Random()表示创建对象,这项任务必须是执行时(运行期)完成的,也就是运行时才创建出对象,才最终明确了obj到底是什么!

可以简单的认为:使用父级类型(不一定是直接父类)来声明,却创建了子类的对象,就是多态!如果涉及接口,则使用接口来声明,却创建了实现类的对象,也是多态!

多态多应用于参数多态、返回值多态、数组多态。

3. 抽象类与接口的区别

抽象类是类,是使用class关键字声明的,接口就是接口,是使用interface关键字声明的!

这2种类型的也存在相似之处:都可以有抽象方法!而抽象方法是必须被实现的,除非实现的那个类自身也是抽象的!

更多是不同之处:

  • 抽象类中即可以有抽象方法,也可以有普通方法;可以有普通的成员变量,也可以有静态常量;无论是属性还是方法,可以使用任何访问权限;接口中所有的成员都是公有的,所有属性都是静态常量,所有方法都是抽象方法!

  • 抽象类是一种特殊的类,符合类的所有特征,例如单继承等等,而接口有另一套语法特征,例如:类与接口的关系是实现关系,使用implements关键字来描述,一个类可以同时实现若干个接口;接口与接口之间也可以有继承关键,使用extends关键字来描述,并且,一个接口可以同时继承多个接口!

在使用的选择方面,也是有不同的:

抽象类终究是一个类,应该体现某种类别!接口是用于定制标准的,是用于描述行为特征和行为模式的!

普通的类,与抽象类,会存在普通类 is a 抽象类的关系,实现类与接口,会存在实现类 has 接口的关系。

Serializable, Comparable

public class Teacher extends Person
public class Student extends Person
public class Driver extends Person
public class Doctor extends Person

public class Person implements 教学, 学习, 驾驶, 医疗 {
}

教学 teacher = new Person();
学习 student = (学习) teacher;

猜你喜欢

转载自www.cnblogs.com/wood-life/p/10290796.html