SSM综合项目实战(TTSC) -- day08 单点登录,注册登录,jsonp

一、单点登录准备工作

1、导入用户表



SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(32) NOT NULL COMMENT '密码,加密存储',
  `phone` varchar(20) DEFAULT NULL COMMENT '注册手机号',
  `email` varchar(50) DEFAULT NULL COMMENT '注册邮箱',
  `created` datetime NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`) USING BTREE,
  UNIQUE KEY `phone` (`phone`) USING BTREE,
  UNIQUE KEY `email` (`email`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='用户表';

2、导入用户的POJO类




package com.taotao.manager.pojo;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Table(name = "tb_user")
public class User extends BasePojo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;

    private String phone;

    private String email;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", password=" + password + ", phone="
                + phone + ", email=" + email + "]";
    }

}

3、创建UserMapper的接口




package com.taotao.sso.mapper;

import com.github.abel533.mapper.Mapper;
import com.taotao.manager.pojo.User;

/**
 * 用户的持久层接口
 * @author Administrator
 *
 */
public interface UserMapper extends Mapper<User> {

	
}

4、创建UserService接口和实现类




package com.taotao.sso.service;

/**
 * 用户的业务层接口
 * 
 * @author Administrator
 *
 */
public interface UserService {

}

package com.taotao.sso.service.impl;

import org.springframework.stereotype.Service;

import com.taotao.sso.service.UserService;

/**
 * 用户业务层实现类
 * @author Administrator
 *
 */
@Service
public class UserServiceImpl implements UserService {

}

5、创建用户的Controller




package com.taotao.sso.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.taotao.sso.service.UserService;

/**
 * 用户的Controller
 * @author Administrator
 *
 */
@Controller
@RequestMapping("user")
public class UserController {

	@Autowired
	private UserService userService;
	
}

6、暴露服务和声明服务的调用






7、修改host文件和nginx的配置文件





二、单点登录接口的实现

1、实现检查数据是否可用

(1)、开发分析

接口文档




接口是校验username、phone、email三个字段是否可用,用户要输入的这三个字段必须是没有被别人使用过的。

我们可以把这个字段作为条件进行查询,如果查询到了,则表示已经有人用了,那么新用户就不能使用,数据不可用,返回false;如果没有查询到,则表示没有被别人用,新用户可以使用,数据可用,返回true。

(2)、实现Controller

	/**
	 * 校验数据是否可用
	 * 
	 * @param param
	 * @param status
	 * @return
	 */
	@RequestMapping(value = "check/{param}/{type}", method = RequestMethod.GET)
	public ResponseEntity<Boolean> check(@PathVariable String param, @PathVariable Integer type) {
		try {
			Boolean bool = this.userService.check(param, type);
			// 如果成功,返回200
			return ResponseEntity.ok(bool);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 失败返回500
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
	}

(3)、实现Service接口和实现类

UserService.java

package com.taotao.sso.service;

/**
 * 用户的业务层接口
 * 
 * @author Administrator
 *
 */
public interface UserService {

	/**
	 * 校验数据是否可用
	 * 
	 * @param param
	 * @param status
	 * @return
	 */
	public Boolean check(String param, Integer type);

}


UserServicImpl.java
package com.taotao.sso.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.taotao.manager.pojo.User;
import com.taotao.sso.mapper.UserMapper;
import com.taotao.sso.service.UserService;

/**
 * 用户业务层实现类
 * 
 * @author Administrator
 *
 */
@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserMapper userMapper;

	/**
	 * 校验数据是否可用
	 * 
	 * @param param
	 * @param status
	 * @return
	 */
	public Boolean check(String param, Integer type) {
		// 声明查询条件
		User user = new User();

		// 设置条件
		switch (type) {
		case 1:
			user.setUsername(param);
			break;
		case 2:
			user.setPhone(param);
			break;
		case 3:
			user.setEmail(param);
			break;
		default:
			break;
		}

		// 执行查询
		Boolean bool = this.userMapper.selectCount(user) == 0;
		
		return bool;
	}

}

2、实现根据ticker查询用户接口

(1)、开发分析




根据ticket查询用户

用户信息保存在redis中,返回的数据是json格式,需要把json格式数据转为对象

(2)、实现Controller

	/**
	 * 根据ticket查询用户
	 * 
	 * @param ticket
	 * @return
	 */
	@RequestMapping(value = "{ticket}", method = RequestMethod.GET)
	public ResponseEntity<User> queryUserByTicket(@PathVariable String ticket) {
		try {
			User user = this.userService.queryUserByTicket(ticket);
			return ResponseEntity.ok(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 失败返回500
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
	}

(3)、实现Service层接口和实现类

	/**
	 * 根据ticket查询用户
	 * 
	 * @param ticket
	 * @return
	 */
	public User queryUserByTicket(String ticket); 


	@Autowired
	private RedisUtils redisUtils;
	
	@Value("${TAOTAO_SSO_TICKET_PRE}")
	private String TAOTAO_SSO_TICKET_PRE;
	
	private static final ObjectMapper MAPPER = new ObjectMapper();
	
	/** 
	 * 根据ticket查询用户 
	 *  
	 * @param ticket 
	 * @return 
	 */  
	public User queryUserByTicket(String ticket) {  
	    //从redis中根据ticket查询用户信息,查询到的是json数据  
	    //需要给redis中的key添加前缀,方便redis的维护和管理  
	    String json = this.redisUtils.get(TAOTAO_SSO_TICKET_PRE + ticket);  
	      
	    //判断json是否为null  
	    if(StringUtils.isNotBlank(json)){  
		try {  
		    //把json转换为对象  
		    User user = MAPPER.readValue(json, User.class);  
		      
		    //如果用户调用该方法,表示用户是活动的,需要重新设置redis中用户的缓存时间,避免每隔固定时间,用户就要重新登录  
		    this.redisUtils.expire(TAOTAO_SSO_TICKET_PRE + ticket, 60*30);  
		      
		    //返回用户对象  
		    return user;  
		} catch (Exception e) {  
		    e.printStackTrace();  
		}  
	    }  
	    //如果没有查询到数据,或者转换异常,返回null  
	    return null;  
	} 

(4)、在redis资源配置文件中配置前缀

#配置redis中用户数据前缀
TAOTAO_SSO_TICKET_PRE=TAOTAO_SSO_TICKET_PRE_


三、首页跳转注册、登录页面

1、在taotao-portal中编写通用页面跳转的Controller代码




package com.taotao.portal.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 通用页面跳转方法
 * 
 * @author Administrator
 *
 */
@Controller
@RequestMapping("page")
public class PageController {

	/**
	 * 通用页面跳转的方法
	 * 
	 * @param pageName
	 * @return
	 */
	@RequestMapping(value = "{pageName}", method = RequestMethod.GET)
	public String toPage(@PathVariable String pageName) {
		return pageName;
	}
}


四、jsonp

1、jsonp在项目中应用的位置

(1)、查看发送ajax请求的url




(2)、在项目中搜索 /user/check 的ajax 所在位置






(3)、查看ajax逻辑,找到 jsonp 所在位置




分析:

分析发现使用的dataType是jsonp,这里使用的是jsonp技术

为什么要使用jsonp呢,这里使用jsonp是为了解决js跨域调用的问题。

2、跨域问题

(1)、什么是跨域

跨域就是跨域名或跨端口号进行调用,例如:

www.taotao.com >> www.jd.com 是跨域

www.taotao.com >> sso.taotao.com 是跨域

www.taotao.com >> www.taotao.com:8080         是跨域

www.taotao.com >> www.taotao.com 不是跨域

只有请求者和被请求者的域名和端口号完全一致,才不是跨域

(2)、跨域有什么问题

js使用Ajax请求进行跨域请求,无法返回数据(json、xml等)。

(3)、为什么会有跨域问题

浏览器基于安全考虑,不允许Ajax请求跨域调用数据(json、xml等)

我们现在碰到的问题就是,www.taotao.com请求sso.taotao.com,因为跨域问题,是无法使用Ajax获取数据的

3、jsonp原理

(1)、jsonp核心原理

js使用Ajax无法跨域调用数据(xml,json等),但是可以跨域调用js数据,js的Ajax请求数据和请求js数据的不同如下图:




(2)、解决js使用Ajax无法跨域获取数据的方法

我们可以通过请求js的方式,进行跨域调用,如下图:




五、单点登录支持jsonp

1、分析

修改单点登录接口,使其支持跨域其实就是使用request获取方法名,再把返回值进行包裹。

我们需要做的事,如下图:




分析发现,我们需要的请求参数名其实就是callback



2、改造UserController.java代码




	/**
	 * 校验数据是否可用
	 * 
	 * @param param
	 * @param status
	 * @return
	 */
	@RequestMapping(value = "check/{param}/{type}", method = RequestMethod.GET)
	public ResponseEntity<String> check(String callback, @PathVariable String param, @PathVariable Integer type) {
		try {
			
			Boolean bool = this.userService.check(param, type);
			//1.接收请求中的callback的值
			//2.判断callback是否为null,如果为null,则表示是普通的访问
			String result = "";
			if(StringUtils.isNotBlank(callback)){
				//如果部位null,表示是jsonp请求
				//3.使用callback包裹返回的json数据,实现跨域调用
				result = callback + "(" + bool +")";
			}else{
				//不是jsonp请求,直接返回数据
				result = "" + bool;
			}
			// 如果成功,返回200
			return ResponseEntity.ok(result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 失败返回500
		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
	}

3、测试效果页面




六、实现用户注册

1、改造页面注册方法的请求url




2、编写用户登录的Controller

(1)、在taotao-portal中加入sso-interface的依赖




(2)、在taotao-portal中编写UserConterller.java

package com.taotao.portal.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.taotao.manager.pojo.User;
import com.taotao.sso.service.UserService;

/**
 * 用户功能的web类
 * 
 * @author Administrator
 *
 */
@Controller
@RequestMapping("user")
public class UserController {

	@Autowired
	private UserService userService;

	/**
	 * 用户注册的方法
	 * 
	 * @param user
	 * @return
	 */
	@RequestMapping(value = "doRegister", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> register(User user) {
		this.userService.saveUser(user);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("status", 200);
		return map;
	}
}

3、在portal系统中声明服务的调用




4、编写UserService层接口和实现类

	/**
	 * 用户注册的方法
	 * 
	 * @param user
	 */
	public void saveUser(User user);

	/**
	 * 用户注册的方法
	 */
	public void saveUser(User user) {
		// 设置用户信息
		user.setCreated(new Date());
		user.setUpdated(user.getCreated());
		// 需要对密码进行加密,加密方法用的是md5Hex(),DigestUtils是commons-codecjar包中的方法
		user.setPassword(DigestUtils.md5Hex(user.getPassword()));

		// 执行保存方法
		this.userMapper.insert(user);
	}

5、测试注册

发现问题:数据保存成功,但页面返回值错误






问题分析:

springmvc底层机制是如果请求路径以.html结尾,系统默认以html的方式响应




问题解决:修改portal项目中web.xml中拦截的路径,添加 /service/* 的拦截路径




同时:修改注册js的url




修改之后从新启动portal项目测试




七、实现用户登录

1、登录页面的代码分析




2、导入操作Cookie的工具类






package com.taotao.portal.utils;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * 
 * Cookie 工具类
 *
 */
public final class CookieUtils {

    /**
     * 得到Cookie的值, 不编码
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
        	 e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue) {
        setCookie(request, response, cookieName, cookieValue, -1);
    }

    /**
     * 设置Cookie的值 在指定时间内生效,但不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    }

    /**
     * 设置Cookie的值 不设置生效时间,但编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, boolean isEncode) {
        setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage, boolean isEncode) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage, String encodeString) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    }

    /**
     * 删除Cookie带cookie域名
     */
    public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName) {
        doSetCookie(request, response, cookieName, "", -1, false);
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     * 
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else if (isEncode) {
                cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
            	String domainName = getDomainName(request);
            	System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                	cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
        	 e.printStackTrace();
        }
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     * 
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
            	String domainName = getDomainName(request);
            	System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                	cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
        	 e.printStackTrace();
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;

        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            serverName = serverName.toLowerCase();
            serverName = serverName.substring(7);
            final int end = serverName.indexOf("/");
            serverName = serverName.substring(0, end);
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = "." + domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }

}

3、编写登录的Controller代码


	@Value("${COOKIE_TICKET}")
	private String COOKIE_TICKET;

	/**
	 * 用户登录的方法
	 * 
	 * @param username
	 * @param password
	 * @return
	 */
	@RequestMapping(value = "doLogin", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> doLogin(HttpServletRequest request, HttpServletResponse response, String username,
			String password) {
		// 调用服务,登录用户,返回登录成功所需要的ticket
		String ticket = this.userService.doLogin(username, password);

		// 创建集合,存放返回数据
		Map<String, Object> map = new HashMap<String, Object>();

		// 判断ticket是否为null
		if (StringUtils.isNotBlank(ticket)) {
			// 不为空,把ticket放入cookie中
			CookieUtils.setCookie(request, response, this.COOKIE_TICKET, ticket, 60 * 60 * 24, true);
			// 封装返回数据
			map.put("status", 200);
		} else {
			// 为空,登录失败,返回结果中不存放任何数据
		}

		return map;
	}

4、配置env.properties资源文件中的cookie的name值




5、编写Service层接口和实现类

	/**
	 * 用户登录的方法
	 * 
	 * @param user
	 */
	public String doLogin(String username, String password);

	@Value("${TAOTAO_SSO_TICKET_INCR}")
	private String TAOTAO_SSO_TICKET_INCR;
	/**
	 * 用户登录的方法
	 */
	public String doLogin(String username, String password) {
		//声明查询条件
		User user = new User();
		user.setUsername(username);
		user.setPassword(DigestUtils.md5Hex(password));
		
		//根据用户名密码执行查询方法
		User result = this.userMapper.selectOne(user);
		
		//判断用户是否登录成功
		if(result != null){
			//利用redis单线程的特点,生成唯一的标识ticket   ticket=随机数+用户id
			long incr = this.redisUtils.incr(this.TAOTAO_SSO_TICKET_INCR);
			String ticket = String.valueOf(incr) + result.getId();
			
			//把ticket和用户信息保存到redis中
			try {
				this.redisUtils.set(TAOTAO_SSO_TICKET_PRE + ticket, MAPPER.writeValueAsString(result),60 * 30);
				//返回数据
				return ticket;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

6、在sso-service中配置资源文件




7、测试用户登录,并且查看是否把ticket存入cookie中

问题出现:可以登录成功,但是cookies中没有ticket的cookie




问题原因:使用debug查看存储cookie过程中,获取的域名为127.0.0.1




问题分析:因为nginx反向代理的时候,没有携带域名

8、解决无法把ticket存入cookie中的问题

在nginx配置文件中加上域名的反向代理



9、测试查看是否有cookie



  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
收货地址管理是电子商务系统中非常重要的一环,用户需要能够方便地添加、修改、删除和选择收货地址。在SSM实战中,我们可以使用Maven构建项目,使用Spring、SpringMVC和MyBatis框架实现收货地址管理功能。 1. 创建数据库表 首先,我们需要在数据库中创建一个地址表,该表包含以下字段: - id:主键,自增长。 - user_id:用户ID,外键,关联用户表。 - name:收货人姓名。 - phone:收货人电话号码。 - province:省份。 - city:城市。 - district:区县。 - address:详细地址。 - is_default:是否为默认地址,0表示不是,1表示是。 2. 创建实体类和Mapper 在Java项目中,我们需要创建一个地址实体类,该类需要包含上述字段对应的属性。同时,我们还需要创建一个地址Mapper接口,用于定义地址操作的基本方法,如添加、删除、修改和查询等。 3. 创建Service接口和实现类 在SSM实战中,我们常常使用Service接口和实现类来封装业务逻辑。在本例中,我们需要创建一个AddressService接口和实现类,用于对地址进行操作,如添加、删除、修改和查询等。 4. 创建Controller类 在SpringMVC中,我们需要创建一个Controller类,用于接收用户请求并调用Service层进行处理。在本例中,我们需要创建一个AddressController类,该类需要包含以下方法: - addAddress:添加地址。 - deleteAddress:删除地址。 - updateAddress:修改地址。 - getAddressList:获取地址列表。 - getDefaultAddress:获取默认地址。 5. 实现前端页面 最后,我们需要在前端页面中实现地址管理功能。我们可以使用HTML、CSS和JavaScript等技术,使用Ajax异步请求后端接口,实现地址的增删改查等操作。 以上就是SSM实战中实现收货地址管理功能的基本步骤,需要注意的是,在实现过程中,我们需要注意安全性和可扩展性等问题。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值